diff -r 15fd0b4496e0 Modules/_randommodule.c --- a/Modules/_randommodule.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Modules/_randommodule.c Sun Sep 30 21:03:36 2012 +0300 @@ -283,7 +283,8 @@ n = newn; if (keyused >= keymax) { unsigned long bigger = keymax << 1; - if ((bigger >> 1) != keymax) { + if ((bigger >> 1) != keymax || + bigger > PY_SSIZE_T_MAX / sizeof(*key)) { PyErr_NoMemory(); goto Done; } diff -r 15fd0b4496e0 Modules/arraymodule.c --- a/Modules/arraymodule.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Modules/arraymodule.c Sun Sep 30 21:03:36 2012 +0300 @@ -423,11 +423,11 @@ return NULL; } - nbytes = size * descr->itemsize; /* Check for overflow */ - if (nbytes / descr->itemsize != (size_t)size) { + if (size > PY_SSIZE_T_MAX / descr->itemsize) { return PyErr_NoMemory(); } + nbytes = size * descr->itemsize; op = (arrayobject *) type->tp_alloc(type, 0); if (op == NULL) { return NULL; @@ -1205,13 +1205,10 @@ char *item = self->ob_item; Py_ssize_t itemsize = self->ob_descr->itemsize; size_t nread; - Py_ssize_t newlength; size_t newbytes; - /* Be careful here about overflow */ - if ((newlength = Py_SIZE(self) + n) <= 0 || - (newbytes = newlength * itemsize) / itemsize != - (size_t)newlength) + if (n > (PY_SSIZE_T_MAX - Py_SIZE(self)) / itemsize) goto nomem; + newbytes = (Py_SIZE(self) + n) * itemsize; PyMem_RESIZE(item, char, newbytes); if (item == NULL) { nomem: diff -r 15fd0b4496e0 Modules/audioop.c --- a/Modules/audioop.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Modules/audioop.c Sun Sep 30 21:03:36 2012 +0300 @@ -1094,8 +1094,7 @@ PyErr_SetString(AudioopError, "# of channels should be >= 1"); return NULL; } - bytes_per_frame = size * nchannels; - if (bytes_per_frame / nchannels != size) { + if (size > INT_MAX / nchannels) { /* This overflow test is rigorously correct because both multiplicands are >= 1. Use the argument names from the docs for the error msg. */ @@ -1103,6 +1102,7 @@ "width * nchannels too big for a C int"); return NULL; } + bytes_per_frame = size * nchannels; if (weightA < 1 || weightB < 0) { PyErr_SetString(AudioopError, "weightA should be >= 1, weightB should be >= 0"); diff -r 15fd0b4496e0 Modules/cPickle.c --- a/Modules/cPickle.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Modules/cPickle.c Sun Sep 30 21:03:36 2012 +0300 @@ -218,14 +218,12 @@ size_t nbytes; PyObject **tmp; + if (self->size == 0 || self->size > (INT_MAX >> 1)) + goto nomemory; bigger = self->size << 1; - if (bigger <= 0) /* was 0, or new value overflows */ - goto nomemory; - if ((int)(size_t)bigger != bigger) + if ((size_t)bigger > PY_SSIZE_T_MAX / sizeof(PyObject *)) goto nomemory; nbytes = (size_t)bigger * sizeof(PyObject *); - if (nbytes / sizeof(PyObject *) != (size_t)bigger) - goto nomemory; tmp = realloc(self->data, nbytes); if (tmp == NULL) goto nomemory; diff -r 15fd0b4496e0 Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Objects/bytearrayobject.c Sun Sep 30 21:03:36 2012 +0300 @@ -357,9 +357,9 @@ if (count < 0) count = 0; mysize = Py_SIZE(self); + if (count != 0 && mysize > PY_SSIZE_T_MAX / count) + return PyErr_NoMemory(); size = mysize * count; - if (count != 0 && size / count != mysize) - return PyErr_NoMemory(); result = (PyByteArrayObject *)PyByteArray_FromStringAndSize(NULL, size); if (result != NULL && size != 0) { if (mysize == 1) @@ -382,9 +382,9 @@ if (count < 0) count = 0; mysize = Py_SIZE(self); + if (count != 0 && mysize > PY_SSIZE_T_MAX / count) + return PyErr_NoMemory(); size = mysize * count; - if (count != 0 && size / count != mysize) - return PyErr_NoMemory(); if (size < self->ob_alloc) { Py_SIZE(self) = size; self->ob_bytes[Py_SIZE(self)] = '\0'; /* Trailing null byte */ @@ -1562,7 +1562,7 @@ { char *self_s, *result_s; Py_ssize_t self_len, result_len; - Py_ssize_t count, i, product; + Py_ssize_t count, i; PyByteArrayObject *result; self_len = PyByteArray_GET_SIZE(self); @@ -1574,18 +1574,13 @@ /* Check for overflow */ /* result_len = count * to_len + self_len; */ - product = count * to_len; - if (product / to_len != count) { + assert(count > 0); + if (to_len > (PY_SSIZE_T_MAX - self_len) / count) { PyErr_SetString(PyExc_OverflowError, "replace string is too long"); return NULL; } - result_len = product + self_len; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, - "replace string is too long"); - return NULL; - } + result_len = count * to_len + self_len; if (! (result = (PyByteArrayObject *) PyByteArray_FromStringAndSize(NULL, result_len)) ) @@ -1815,7 +1810,7 @@ char *self_s, *result_s; char *start, *next, *end; Py_ssize_t self_len, result_len; - Py_ssize_t count, product; + Py_ssize_t count; PyByteArrayObject *result; self_s = PyByteArray_AS_STRING(self); @@ -1829,16 +1824,12 @@ /* use the difference between current and new, hence the "-1" */ /* result_len = self_len + count * (to_len-1) */ - product = count * (to_len-1); - if (product / (to_len-1) != count) { + assert(count > 0); + if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) { PyErr_SetString(PyExc_OverflowError, "replace bytes is too long"); return NULL; } - result_len = self_len + product; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, "replace bytes is too long"); - return NULL; - } + result_len = self_len + count * (to_len - 1); if ( (result = (PyByteArrayObject *) PyByteArray_FromStringAndSize(NULL, result_len)) == NULL) @@ -1882,7 +1873,7 @@ char *self_s, *result_s; char *start, *next, *end; Py_ssize_t self_len, result_len; - Py_ssize_t count, offset, product; + Py_ssize_t count, offset; PyByteArrayObject *result; self_s = PyByteArray_AS_STRING(self); @@ -1899,16 +1890,12 @@ /* Check for overflow */ /* result_len = self_len + count * (to_len-from_len) */ - product = count * (to_len-from_len); - if (product / (to_len-from_len) != count) { + assert(count > 0); + if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) { PyErr_SetString(PyExc_OverflowError, "replace bytes is too long"); return NULL; } - result_len = self_len + product; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, "replace bytes is too long"); - return NULL; - } + result_len = self_len + count * (to_len - from_len); if ( (result = (PyByteArrayObject *) PyByteArray_FromStringAndSize(NULL, result_len)) == NULL) diff -r 15fd0b4496e0 Objects/longobject.c --- a/Objects/longobject.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Objects/longobject.c Sun Sep 30 21:03:36 2012 +0300 @@ -483,10 +483,9 @@ assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); if (ndigits > 0) { digit msd = v->ob_digit[ndigits - 1]; - - result = (ndigits - 1) * PyLong_SHIFT; - if (result / PyLong_SHIFT != (size_t)(ndigits - 1)) + if ((size_t)(ndigits - 1) > PY_SIZE_MAX / (size_t)PyLong_SHIFT) goto Overflow; + result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT; do { ++result; if (result == 0) diff -r 15fd0b4496e0 Objects/stringlib/formatter.h --- a/Objects/stringlib/formatter.h Sun Sep 30 09:03:09 2012 +0200 +++ b/Objects/stringlib/formatter.h Sun Sep 30 21:03:36 2012 +0300 @@ -73,7 +73,7 @@ get_integer(STRINGLIB_CHAR **ptr, STRINGLIB_CHAR *end, Py_ssize_t *result) { - Py_ssize_t accumulator, digitval, oldaccumulator; + Py_ssize_t accumulator, digitval; int numdigits; accumulator = numdigits = 0; for (;;(*ptr)++, numdigits++) { @@ -83,19 +83,17 @@ if (digitval < 0) break; /* - 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; } *result = accumulator; return numdigits; diff -r 15fd0b4496e0 Objects/stringlib/string_format.h --- a/Objects/stringlib/string_format.h Sun Sep 30 09:03:09 2012 +0200 +++ b/Objects/stringlib/string_format.h Sun Sep 30 21:03:36 2012 +0300 @@ -197,7 +197,6 @@ { Py_ssize_t accumulator = 0; Py_ssize_t digitval; - Py_ssize_t oldaccumulator; STRINGLIB_CHAR *p; /* empty string is an error */ @@ -209,19 +208,17 @@ 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; } diff -r 15fd0b4496e0 Objects/stringobject.c --- a/Objects/stringobject.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Objects/stringobject.c Sun Sep 30 21:03:36 2012 +0300 @@ -922,13 +922,15 @@ PyString_Repr(PyObject *obj, int smartquotes) { register PyStringObject* op = (PyStringObject*) obj; - size_t newsize = 2 + 4 * Py_SIZE(op); + size_t newsize; PyObject *v; - if (newsize > PY_SSIZE_T_MAX || newsize / 4 != Py_SIZE(op)) { + if (Py_SIZE(op) > (PY_SSIZE_T_MAX - 2) / 4) { + PyErr_SetString(PyExc_OverflowError, "string is too large to make repr"); return NULL; } + newsize = 2 + 4 * Py_SIZE(op); v = PyString_FromStringAndSize((char *)NULL, newsize); if (v == NULL) { return NULL; @@ -1079,12 +1081,12 @@ /* watch out for overflows: the size can overflow int, * and the # of bytes needed can overflow size_t */ - size = Py_SIZE(a) * n; - if (n && size / n != Py_SIZE(a)) { + if (n > 0 && Py_SIZE(a) > PY_SSIZE_T_MAX / n) { PyErr_SetString(PyExc_OverflowError, "repeated string is too long"); return NULL; } + size = Py_SIZE(a) * n; if (size == Py_SIZE(a) && PyString_CheckExact(a)) { Py_INCREF(a); return (PyObject *)a; @@ -2354,7 +2356,7 @@ { char *self_s, *result_s; Py_ssize_t self_len, result_len; - Py_ssize_t count, i, product; + Py_ssize_t count, i; PyStringObject *result; self_len = PyString_GET_SIZE(self); @@ -2366,18 +2368,13 @@ /* Check for overflow */ /* result_len = count * to_len + self_len; */ - product = count * to_len; - if (product / to_len != count) { + assert(count > 0); + if (to_len > (PY_SSIZE_T_MAX - self_len) / count) { PyErr_SetString(PyExc_OverflowError, "replace string is too long"); return NULL; } - result_len = product + self_len; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, - "replace string is too long"); - return NULL; - } + result_len = count * to_len + self_len; if (! (result = (PyStringObject *) PyString_FromStringAndSize(NULL, result_len)) ) @@ -2606,7 +2603,7 @@ char *self_s, *result_s; char *start, *next, *end; Py_ssize_t self_len, result_len; - Py_ssize_t count, product; + Py_ssize_t count; PyStringObject *result; self_s = PyString_AS_STRING(self); @@ -2620,16 +2617,12 @@ /* use the difference between current and new, hence the "-1" */ /* result_len = self_len + count * (to_len-1) */ - product = count * (to_len-1); - if (product / (to_len-1) != count) { + assert(count > 0); + if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) { PyErr_SetString(PyExc_OverflowError, "replace string is too long"); return NULL; } - result_len = self_len + product; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, "replace string is too long"); - return NULL; - } + result_len = self_len + count * (to_len - 1); if ( (result = (PyStringObject *) PyString_FromStringAndSize(NULL, result_len)) == NULL) @@ -2672,7 +2665,7 @@ char *self_s, *result_s; char *start, *next, *end; Py_ssize_t self_len, result_len; - Py_ssize_t count, offset, product; + Py_ssize_t count, offset; PyStringObject *result; self_s = PyString_AS_STRING(self); @@ -2689,16 +2682,12 @@ /* Check for overflow */ /* result_len = self_len + count * (to_len-from_len) */ - product = count * (to_len-from_len); - if (product / (to_len-from_len) != count) { + assert(count > 0); + if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) { PyErr_SetString(PyExc_OverflowError, "replace string is too long"); return NULL; } - result_len = self_len + product; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, "replace string is too long"); - return NULL; - } + result_len = self_len + count * (to_len-from_len); if ( (result = (PyStringObject *) PyString_FromStringAndSize(NULL, result_len)) == NULL) @@ -4369,7 +4358,10 @@ c = Py_CHARMASK(*fmt++); if (!isdigit(c)) break; - if ((width*10) / 10 != width) { + /* Since c is unsigned, the RHS would end up as unsigned, + mixing signed and unsigned comparison. Since c is between + '0' and '9', casting to int is safe. */ + if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) { PyErr_SetString( PyExc_ValueError, "width too big"); @@ -4404,7 +4396,7 @@ c = Py_CHARMASK(*fmt++); if (!isdigit(c)) break; - if ((prec*10) / 10 != prec) { + if (prec > (INT_MAX - ((int)c - '0')) / 10) { PyErr_SetString( PyExc_ValueError, "prec too big"); diff -r 15fd0b4496e0 Objects/tupleobject.c --- a/Objects/tupleobject.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Objects/tupleobject.c Sun Sep 30 21:03:36 2012 +0300 @@ -79,11 +79,9 @@ else #endif { - Py_ssize_t nbytes = size * sizeof(PyObject *); /* Check for overflow */ - if (nbytes / sizeof(PyObject *) != (size_t)size || - (nbytes > PY_SSIZE_T_MAX - sizeof(PyTupleObject) - sizeof(PyObject *))) - { + if (size > (PY_SSIZE_T_MAX - sizeof(PyTupleObject) - + sizeof(PyObject *)) / sizeof(PyObject *)) { return PyErr_NoMemory(); } @@ -491,7 +489,7 @@ return PyTuple_New(0); } size = Py_SIZE(a) * n; - if (size/Py_SIZE(a) != n) + if (n > PY_SSIZE_T_MAX / Py_SIZE(a)) return PyErr_NoMemory(); np = (PyTupleObject *) PyTuple_New(size); if (np == NULL) diff -r 15fd0b4496e0 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Sun Sep 30 09:03:09 2012 +0200 +++ b/Objects/unicodeobject.c Sun Sep 30 21:03:36 2012 +0300 @@ -1758,8 +1758,6 @@ const char *errors) { PyObject *v; - /* It might be possible to tighten this worst case */ - Py_ssize_t allocated = 8 * size; int inShift = 0; Py_ssize_t i = 0; unsigned int base64bits = 0; @@ -1767,13 +1765,14 @@ char * out; char * start; - if (allocated / 8 != size) + /* It might be possible to tighten this worst case */ + if (size > PY_SSIZE_T_MAX / 8) return PyErr_NoMemory(); if (size == 0) return PyString_FromStringAndSize(NULL, 0); - v = PyString_FromStringAndSize(NULL, allocated); + v = PyString_FromStringAndSize(NULL, size * 8); if (v == NULL) return NULL; @@ -2097,10 +2096,9 @@ } else { /* Overallocate on the heap, and give the excess back at the end. */ - nallocated = size * 4; - if (nallocated / 4 != size) /* overflow! */ + if (size > PY_SSIZE_T_MAX / 4) return PyErr_NoMemory(); - v = PyString_FromStringAndSize(NULL, nallocated); + v = PyString_FromStringAndSize(NULL, size * 4); if (v == NULL) return NULL; p = PyString_AS_STRING(v); @@ -2360,7 +2358,7 @@ { PyObject *v; unsigned char *p; - Py_ssize_t nsize, bytesize; + Py_ssize_t nsize; #ifndef Py_UNICODE_WIDE Py_ssize_t i, pairs; #else @@ -2391,10 +2389,9 @@ pairs++; #endif nsize = (size - pairs + (byteorder == 0)); - bytesize = nsize * 4; - if (bytesize / 4 != nsize) + if (nsize > PY_SSIZE_T_MAX / 4) return PyErr_NoMemory(); - v = PyString_FromStringAndSize(NULL, bytesize); + v = PyString_FromStringAndSize(NULL, nsize * 4); if (v == NULL) return NULL; @@ -2634,7 +2631,7 @@ { PyObject *v; unsigned char *p; - Py_ssize_t nsize, bytesize; + Py_ssize_t nsize; #ifdef Py_UNICODE_WIDE Py_ssize_t i, pairs; #else @@ -2664,10 +2661,9 @@ size > PY_SSIZE_T_MAX - pairs - (byteorder == 0)) return PyErr_NoMemory(); nsize = size + pairs + (byteorder == 0); - bytesize = nsize * 2; - if (bytesize / 2 != nsize) + if (nsize > PY_SSIZE_T_MAX / 2) return PyErr_NoMemory(); - v = PyString_FromStringAndSize(NULL, bytesize); + v = PyString_FromStringAndSize(NULL, nsize * 2); if (v == NULL) return NULL; @@ -5836,7 +5832,7 @@ } else { Py_ssize_t n, i, j; - Py_ssize_t product, new_size, delta; + Py_ssize_t new_size, delta; Py_UNICODE *p; /* replace strings */ @@ -5849,18 +5845,14 @@ if (delta == 0) { new_size = self->length; } else { - product = n * (str2->length - str1->length); - if ((product / (str2->length - str1->length)) != n) { + if (str2->length > str1->length && + str2->length - str1->length > + (PY_SSIZE_T_MAX - self->length) / n) { PyErr_SetString(PyExc_OverflowError, "replace string is too long"); return NULL; } - new_size = self->length + product; - if (new_size < 0) { - PyErr_SetString(PyExc_OverflowError, - "replace string is too long"); - return NULL; - } + new_size = self->length + n * (str2->length - str1->length); } u = _PyUnicode_New(new_size); if (!u) @@ -7105,7 +7097,6 @@ PyUnicodeObject *u; Py_UNICODE *p; Py_ssize_t nchars; - size_t nbytes; if (len < 0) len = 0; @@ -7119,14 +7110,13 @@ /* ensure # of chars needed doesn't overflow int and # of bytes * needed doesn't overflow size_t */ - nchars = len * str->length; - if (len && nchars / len != str->length) { + if (len && str->length > PY_SSIZE_T_MAX / len) { PyErr_SetString(PyExc_OverflowError, "repeated string is too long"); return NULL; } - nbytes = (nchars + 1) * sizeof(Py_UNICODE); - if (nbytes / sizeof(Py_UNICODE) != (size_t)(nchars + 1)) { + nchars = len * str->length; + if (nchars > PY_SSIZE_T_MAX / sizeof(Py_UNICODE) - 1) { PyErr_SetString(PyExc_OverflowError, "repeated string is too long"); return NULL; @@ -8394,7 +8384,10 @@ c = *fmt++; if (c < '0' || c > '9') break; - if ((width*10) / 10 != width) { + /* Since c is unsigned, the RHS would end up as unsigned, + mixing signed and unsigned comparison. Since c is between + '0' and '9', casting to int is safe. */ + if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) { PyErr_SetString(PyExc_ValueError, "width too big"); goto onError; @@ -8427,7 +8420,7 @@ c = *fmt++; if (c < '0' || c > '9') break; - if ((prec*10) / 10 != prec) { + if (prec > (INT_MAX - ((int)c - '0')) / 10) { PyErr_SetString(PyExc_ValueError, "prec too big"); goto onError;