bpo-31293: Fix crashes in truediv and mul of a timedelta by a float with a bad as_integer_ratio() method. (#3227)

This commit is contained in:
Oren Milman 2017-09-19 15:58:11 +03:00 committed by Serhiy Storchaka
parent 9974e1bcf3
commit 865e4b4f63
3 changed files with 55 additions and 4 deletions

View File

@ -866,6 +866,26 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
self.assertRaises(TypeError, divmod, t, 10) 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 # date tests

View File

@ -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.

View File

@ -1650,6 +1650,33 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
return result; return result;
} }
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 * static PyObject *
multiply_float_timedelta(PyObject *floatobj, PyDateTime_Delta *delta) multiply_float_timedelta(PyObject *floatobj, PyDateTime_Delta *delta)
{ {
@ -1660,9 +1687,10 @@ multiply_float_timedelta(PyObject *floatobj, PyDateTime_Delta *delta)
pyus_in = delta_to_microseconds(delta); pyus_in = delta_to_microseconds(delta);
if (pyus_in == NULL) if (pyus_in == NULL)
return NULL; return NULL;
ratio = _PyObject_CallMethodId(floatobj, &PyId_as_integer_ratio, NULL); ratio = get_float_as_integer_ratio(floatobj);
if (ratio == NULL) if (ratio == NULL) {
goto error; goto error;
}
temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, 0)); temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, 0));
Py_DECREF(pyus_in); Py_DECREF(pyus_in);
pyus_in = NULL; pyus_in = NULL;
@ -1758,9 +1786,10 @@ truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *f)
pyus_in = delta_to_microseconds(delta); pyus_in = delta_to_microseconds(delta);
if (pyus_in == NULL) if (pyus_in == NULL)
return NULL; return NULL;
ratio = _PyObject_CallMethodId(f, &PyId_as_integer_ratio, NULL); ratio = get_float_as_integer_ratio(f);
if (ratio == NULL) if (ratio == NULL) {
goto error; goto error;
}
temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, 1)); temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, 1));
Py_DECREF(pyus_in); Py_DECREF(pyus_in);
pyus_in = NULL; pyus_in = NULL;