From c7d93b761413834e0ac39f5fc648565a2843121f Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 25 Sep 2011 15:34:32 +0100 Subject: [PATCH] Issue #1621: Fix undefined behaviour from signed overflow in datetime module hashes, array and list iterations, and get_integer (stringlib/string_format.h) --- Modules/_datetimemodule.c | 8 ++++---- Modules/arraymodule.c | 2 +- Objects/listobject.c | 6 +++--- Objects/stringlib/string_format.h | 14 ++++++-------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 718dfe2d03a..26e0ed02926 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -2746,13 +2746,13 @@ static Py_hash_t generic_hash(unsigned char *data, int len) { register unsigned char *p; - register Py_hash_t x; + register Py_uhash_t x; p = (unsigned char *) data; - x = *p << 7; + x = (Py_uhash_t)*p << 7; while (--len >= 0) - x = (1000003*x) ^ *p++; - x ^= len; + x = (1000003U*x) ^ (Py_uhash_t)*p++; + x ^= (Py_uhash_t)len; if (x == -1) x = -2; diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 5748a3c0475..8806bd5f854 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2351,7 +2351,7 @@ array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value) self->ob_item + (cur + 1) * itemsize, lim * itemsize); } - cur = start + slicelength * step; + cur = start + (size_t)slicelength * step; if (cur < (size_t)Py_SIZE(self)) { memmove(self->ob_item + (cur-slicelength) * itemsize, self->ob_item + cur * itemsize, diff --git a/Objects/listobject.c b/Objects/listobject.c index cada70857cc..1c516e962b0 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2434,7 +2434,7 @@ list_subscript(PyListObject* self, PyObject* item) src = self->ob_item; dest = ((PyListObject *)result)->ob_item; for (cur = start, i = 0; i < slicelength; - cur += step, i++) { + cur += (size_t)step, i++) { it = src[cur]; Py_INCREF(it); dest[i] = it; @@ -2525,7 +2525,7 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) self->ob_item + cur + 1, lim * sizeof(PyObject *)); } - cur = start + slicelength*step; + cur = start + (size_t)slicelength * step; if (cur < (size_t)Py_SIZE(self)) { memmove(self->ob_item + cur - slicelength, self->ob_item + cur, @@ -2589,7 +2589,7 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) selfitems = self->ob_item; seqitems = PySequence_Fast_ITEMS(seq); for (cur = start, i = 0; i < slicelength; - cur += step, i++) { + cur += (size_t)step, i++) { garbage[i] = selfitems[cur]; ins = seqitems[i]; Py_INCREF(ins); diff --git a/Objects/stringlib/string_format.h b/Objects/stringlib/string_format.h index 6c7adcb01ed..d992b6f53c3 100644 --- a/Objects/stringlib/string_format.h +++ b/Objects/stringlib/string_format.h @@ -209,19 +209,17 @@ get_integer(const SubString *str) if (digitval < 0) return -1; /* - This trick was copied from old Unicode format code. It's cute, - but would really suck on an old machine with a slow divide - implementation. Fortunately, in the normal case we do not - expect too many digits. + Detect possible overflow before it happens: + + accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if + accumulator > (PY_SSIZE_T_MAX - digitval) / 10. */ - oldaccumulator = accumulator; - accumulator *= 10; - if ((accumulator+10)/10 != oldaccumulator+1) { + if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) { PyErr_Format(PyExc_ValueError, "Too many decimal digits in format string"); return -1; } - accumulator += digitval; + accumulator = accumulator * 10 + digitval; } return accumulator; }