bpo-31293: Fix crashes in truediv and mul of a timedelta by a float with a bad as_integer_ratio() method#3227
Conversation
| class BadFloat(float): | ||
| def as_integer_ratio(self): | ||
| return 1 << 1000 | ||
| self.assertRaises(TypeError, truediv, timedelta(), BadFloat()) |
There was a problem hiding this comment.
The modern style to test for exceptions is to use a with assertRaises(..) block:
with self.assertRaises(TypeError):
timedelta() / BadFloat()| goto error; | ||
| if (!PyTuple_Check(ratio)) { | ||
| PyErr_SetString(PyExc_TypeError, | ||
| "Can't multiply timedelta object by float with " |
There was a problem hiding this comment.
It looks like other error messages in this file start with a lowercase letter. Let's keep the style consistent.
I also wonder if a better message would be "unexpected return type from as_integer_ratio(): expected tuple, got %s".
|
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
|
I didn't expect the Spanish Inquisition! |
|
Nobody expects the Spanish Inquisition! @abalkin: please review the changes made to this pull request. |
| ratio = _PyObject_CallMethodId(floatobj, &PyId_as_integer_ratio, NULL); | ||
| if (ratio == NULL) | ||
| goto error; | ||
| if (!PyTuple_Check(ratio)) { |
There was a problem hiding this comment.
This is not enough. The size of the tuple should be 2.
Perhaps the code can be shared in multiply_float_timedelta() and divide_timedelta_int().
There was a problem hiding this comment.
how can code be shared between these two functions? (I wrote a helper-function to share my patch's code between multiply_float_timedelta() and truedivide_timedelta_float().)
There was a problem hiding this comment.
The code of multiply_float_timedelta() and divide_timedelta_int() is almost the same. It is enough a one boolean parameter to distinguish multiplication from division. All code can be moved in a separate function, and multiply_float_timedelta() and divide_timedelta_int() will call it with additional argument 0 or 1.
Usually a refactoring is made only in develop version, but I think this one can be done in a bugfix change. It is enough simple and can help to fix other bugs if they will be found. What are your thoughts @abalkin?
|
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase And if you don't make the requested changes, you will be put in the comfy chair! |
|
I am working to fix the problems that Serhiy pointed out. please don't merge. |
…the ratio checks inside a helper-func
|
I didn't expect the Spanish Inquisition! |
|
Nobody expects the Spanish Inquisition! @serhiy-storchaka, @abalkin: please review the changes made to this pull request. |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
LGTM. I have added just a nitpick.
| def test_issue31293(self): | ||
| # The interpreter shouldn't crash in case a timedelta is divided or | ||
| # multiplied by a float with a bad as_integer_ratio() method. | ||
| def _get_bad_float(bad_ratio): |
There was a problem hiding this comment.
No starting underscore is needed.
|
Thanks @orenmn for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.6. |
…loat with a bad as_integer_ratio() method. (pythonGH-3227) (cherry picked from commit 865e4b4)
|
GH-3654 is a backport of this pull request to the 3.6 branch. |
| with self.assertRaises(TypeError): | ||
| timedelta() * get_bad_float(1 << 1000) | ||
|
|
||
| for bad_ratio in [(), (42, ), (1, 2, 3)]: |
There was a problem hiding this comment.
What would happen if as_integer_ratio() returns a pair of non-integers? A pair of strings? A pair of floats? Could you add tests for these scenarios?
There was a problem hiding this comment.
TypeError will be raised on the attempt to divide on a string.
It doesn't matter what errors are raised with a bad as_integer_ratio(), but the code shouldn't crash.
|
Thanks @orenmn for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.6. |
|
Sorry, @orenmn and @serhiy-storchaka, I could not cleanly backport this to |
_datetimemodule.c- add checks whether as_integer_ratio() returned a tuple.datetimetester.py- add tests to verify that the crashes are no more.https://bugs.python.org/issue31293