From cf0595448ab5fa37134b9045fcc9c7f220bc0206 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 19 Oct 2018 00:04:59 +0300 Subject: [PATCH] bpo-35021: Fix assertion failures in _datetimemodule.c. The result of multiplication and division of an integer and an instane of integer subclass can be not exact integer. The type of the right operand takes precedence when it is a subclass of the type of the left operand. Use PyLong slots explicitly to get an exact integer. --- Lib/test/datetimetester.py | 11 +++++++++++ Modules/_datetimemodule.c | 26 +++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 9c6e71c54d79d3e..bd4ce08290abb46 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -893,8 +893,16 @@ def test_issue31752(self): class BadInt(int): def __mul__(self, other): return Prod() + def __rmul__(self, other): + return Prod() + def __floordiv__(self, other): + return Prod() + def __rfloordiv__(self, other): + return Prod() class Prod: + def __add__(self, other): + return Sum() def __radd__(self, other): return Sum() @@ -906,6 +914,9 @@ def __divmod__(self, other): timedelta(microseconds=BadInt(1)) timedelta(hours=BadInt(1)) timedelta(weeks=BadInt(1)) + timedelta(1) * BadInt(1) + BadInt(1) * timedelta(1) + timedelta(1) // BadInt(1) ############################################################################# diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index b7c59f1bd8626d5..c5e813c766a0d2e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1857,6 +1857,26 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) #define microseconds_to_delta(pymicros) \ microseconds_to_delta_ex(pymicros, &PyDateTime_DeltaType) +/* Don't use PyNumber_Multiply() because of possible + overridden operators in int subclasses. */ +static PyObject * +integer_multiply(PyObject *a, PyObject *b) +{ + assert(PyLong_Check(a)); + assert(PyLong_Check(b)); + return PyLong_Type.tp_as_number->nb_multiply(a, b); +} + +/* Don't use PyNumber_FloorDivide() because of possible + overridden operators in int subclasses. */ +static PyObject * +integer_divide(PyObject *a, PyObject *b) +{ + assert(PyLong_Check(a)); + assert(PyLong_Check(b)); + return PyLong_Type.tp_as_number->nb_floor_divide(a, b); +} + static PyObject * multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) { @@ -1868,7 +1888,7 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) if (pyus_in == NULL) return NULL; - pyus_out = PyNumber_Multiply(pyus_in, intobj); + pyus_out = integer_multiply(pyus_in, intobj); Py_DECREF(pyus_in); if (pyus_out == NULL) return NULL; @@ -1949,7 +1969,7 @@ divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) if (pyus_in == NULL) return NULL; - pyus_out = PyNumber_FloorDivide(pyus_in, intobj); + pyus_out = integer_divide(pyus_in, intobj); Py_DECREF(pyus_in); if (pyus_out == NULL) return NULL; @@ -2309,7 +2329,7 @@ accum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor, assert(num != NULL); if (PyLong_Check(num)) { - prod = PyNumber_Multiply(factor, num); + prod = integer_multiply(num, factor); if (prod == NULL) return NULL; assert(PyLong_CheckExact(prod));