diff options
author | Oren Milman <orenmn@gmail.com> | 2017-09-19 12:58:11 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2017-09-19 12:58:11 (GMT) |
commit | 865e4b4f630e2ae91e61239258abb58b488f1d65 (patch) | |
tree | 3c3ae126a58e5a9e7dddef58d305fc6faafad54e | |
parent | 9974e1bcf3d0cec9b38b39b39b7ec8a1ebd9ef54 (diff) | |
download | cpython-865e4b4f630e2ae91e61239258abb58b488f1d65.zip cpython-865e4b4f630e2ae91e61239258abb58b488f1d65.tar.gz cpython-865e4b4f630e2ae91e61239258abb58b488f1d65.tar.bz2 |
bpo-31293: Fix crashes in truediv and mul of a timedelta by a float with a bad as_integer_ratio() method. (#3227)
-rw-r--r-- | Lib/test/datetimetester.py | 20 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2017-08-28-17-51-42.bpo-31293.eMYZXj.rst | 2 | ||||
-rw-r--r-- | Modules/_datetimemodule.c | 37 |
3 files changed, 55 insertions, 4 deletions
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 29b70e1..a042efd 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -866,6 +866,26 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase): self.assertRaises(TypeError, divmod, t, 10) + 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): + class BadFloat(float): + def as_integer_ratio(self): + return bad_ratio + return BadFloat() + + with self.assertRaises(TypeError): + timedelta() / get_bad_float(1 << 1000) + with self.assertRaises(TypeError): + timedelta() * get_bad_float(1 << 1000) + + for bad_ratio in [(), (42, ), (1, 2, 3)]: + with self.assertRaises(ValueError): + timedelta() / get_bad_float(bad_ratio) + with self.assertRaises(ValueError): + timedelta() * get_bad_float(bad_ratio) + ############################################################################# # date tests diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-08-28-17-51-42.bpo-31293.eMYZXj.rst b/Misc/NEWS.d/next/Core and Builtins/2017-08-28-17-51-42.bpo-31293.eMYZXj.rst new file mode 100644 index 0000000..28b7bfb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-08-28-17-51-42.bpo-31293.eMYZXj.rst @@ -0,0 +1,2 @@ +Fix crashes in true division and multiplication of a timedelta object by a +float with a bad as_integer_ratio() method. Patch by Oren Milman. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 619ac84..3dd7f82 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1651,6 +1651,33 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) } static PyObject * +get_float_as_integer_ratio(PyObject *floatobj) +{ + PyObject *ratio; + + assert(floatobj && PyFloat_Check(floatobj)); + ratio = _PyObject_CallMethodId(floatobj, &PyId_as_integer_ratio, NULL); + if (ratio == NULL) { + return NULL; + } + if (!PyTuple_Check(ratio)) { + PyErr_Format(PyExc_TypeError, + "unexpected return type from as_integer_ratio(): " + "expected tuple, got '%.200s'", + Py_TYPE(ratio)->tp_name); + Py_DECREF(ratio); + return NULL; + } + if (PyTuple_Size(ratio) != 2) { + PyErr_SetString(PyExc_ValueError, + "as_integer_ratio() must return a 2-tuple"); + Py_DECREF(ratio); + return NULL; + } + return ratio; +} + +static PyObject * multiply_float_timedelta(PyObject *floatobj, PyDateTime_Delta *delta) { PyObject *result = NULL; @@ -1660,9 +1687,10 @@ multiply_float_timedelta(PyObject *floatobj, PyDateTime_Delta *delta) pyus_in = delta_to_microseconds(delta); if (pyus_in == NULL) return NULL; - ratio = _PyObject_CallMethodId(floatobj, &PyId_as_integer_ratio, NULL); - if (ratio == NULL) + ratio = get_float_as_integer_ratio(floatobj); + if (ratio == NULL) { goto error; + } temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, 0)); Py_DECREF(pyus_in); pyus_in = NULL; @@ -1758,9 +1786,10 @@ truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *f) pyus_in = delta_to_microseconds(delta); if (pyus_in == NULL) return NULL; - ratio = _PyObject_CallMethodId(f, &PyId_as_integer_ratio, NULL); - if (ratio == NULL) + ratio = get_float_as_integer_ratio(f); + if (ratio == NULL) { goto error; + } temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, 1)); Py_DECREF(pyus_in); pyus_in = NULL; |