diff options
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/longobject.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c index 459eed9..4862b76 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4277,15 +4277,54 @@ long_bool(PyLongObject *v) return Py_SIZE(v) != 0; } +/* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */ +static int +divmod_shift(PyLongObject *shiftby, Py_ssize_t *wordshift, digit *remshift) +{ + assert(PyLong_Check((PyObject *)shiftby)); + assert(Py_SIZE(shiftby) >= 0); + Py_ssize_t lshiftby = PyLong_AsSsize_t((PyObject *)shiftby); + if (lshiftby >= 0) { + *wordshift = lshiftby / PyLong_SHIFT; + *remshift = lshiftby % PyLong_SHIFT; + return 0; + } + /* PyLong_Check(shiftby) is true and Py_SIZE(shiftby) >= 0, so it must + be that PyLong_AsSsize_t raised an OverflowError. */ + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_Clear(); + PyLongObject *wordshift_obj = divrem1(shiftby, PyLong_SHIFT, remshift); + if (wordshift_obj == NULL) { + return -1; + } + *wordshift = PyLong_AsSsize_t((PyObject *)wordshift_obj); + Py_DECREF(wordshift_obj); + if (*wordshift >= 0 && *wordshift < PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(digit)) { + return 0; + } + PyErr_Clear(); + /* Clip the value. With such large wordshift the right shift + returns 0 and the left shift raises an error in _PyLong_New(). */ + *wordshift = PY_SSIZE_T_MAX / sizeof(digit); + *remshift = 0; + return 0; +} + static PyObject * long_rshift(PyLongObject *a, PyLongObject *b) { PyLongObject *z = NULL; - Py_ssize_t shiftby, newsize, wordshift, loshift, hishift, i, j; - digit lomask, himask; + Py_ssize_t newsize, wordshift, hishift, i, j; + digit loshift, lomask, himask; CHECK_BINOP(a, b); + if (Py_SIZE(b) < 0) { + PyErr_SetString(PyExc_ValueError, + "negative shift count"); + return NULL; + } + if (Py_SIZE(a) < 0) { /* Right shifting negative numbers is harder */ PyLongObject *a1, *a2; @@ -4300,19 +4339,11 @@ long_rshift(PyLongObject *a, PyLongObject *b) Py_DECREF(a2); } else { - shiftby = PyLong_AsSsize_t((PyObject *)b); - if (shiftby == -1L && PyErr_Occurred()) - return NULL; - if (shiftby < 0) { - PyErr_SetString(PyExc_ValueError, - "negative shift count"); + if (divmod_shift(b, &wordshift, &loshift) < 0) return NULL; - } - wordshift = shiftby / PyLong_SHIFT; - newsize = Py_ABS(Py_SIZE(a)) - wordshift; + newsize = Py_SIZE(a) - wordshift; if (newsize <= 0) return PyLong_FromLong(0); - loshift = shiftby % PyLong_SHIFT; hishift = PyLong_SHIFT - loshift; lomask = ((digit)1 << hishift) - 1; himask = PyLong_MASK ^ lomask; @@ -4336,27 +4367,22 @@ long_lshift(PyObject *v, PyObject *w) PyLongObject *a = (PyLongObject*)v; PyLongObject *b = (PyLongObject*)w; PyLongObject *z = NULL; - Py_ssize_t shiftby, oldsize, newsize, wordshift, remshift, i, j; + Py_ssize_t oldsize, newsize, wordshift, i, j; + digit remshift; twodigits accum; CHECK_BINOP(a, b); - shiftby = PyLong_AsSsize_t((PyObject *)b); - if (shiftby == -1L && PyErr_Occurred()) - return NULL; - if (shiftby < 0) { + if (Py_SIZE(b) < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } - if (Py_SIZE(a) == 0) { return PyLong_FromLong(0); } - /* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */ - wordshift = shiftby / PyLong_SHIFT; - remshift = shiftby - wordshift * PyLong_SHIFT; - + if (divmod_shift(b, &wordshift, &remshift) < 0) + return NULL; oldsize = Py_ABS(Py_SIZE(a)); newsize = oldsize + wordshift; if (remshift) |