changeset: 102333:130d97217e36 branch: 2.7 parent: 102322:f7f0f1aecbfa user: Serhiy Storchaka date: Tue Jul 12 15:46:57 2016 +0300 files: Misc/NEWS Objects/bytearrayobject.c Objects/stringobject.c Objects/unicodeobject.c description: Issue #27473: Fixed possible integer overflow in str, unicode and bytearray concatenations and repetitions. Based on patch by Xiang Zhang. diff -r f7f0f1aecbfa -r 130d97217e36 Misc/NEWS --- a/Misc/NEWS Mon Jul 11 07:51:37 2016 +0000 +++ b/Misc/NEWS Tue Jul 12 15:46:57 2016 +0300 @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #27473: Fixed possible integer overflow in str, unicode and bytearray + concatenations and repetitions. Based on patch by Xiang Zhang. + - Issue #23908: os functions, open() and the io.FileIO constructor now reject unicode paths with embedded null character on Windows instead of silently truncating them. diff -r f7f0f1aecbfa -r 130d97217e36 Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Mon Jul 11 07:51:37 2016 +0000 +++ b/Objects/bytearrayobject.c Tue Jul 12 15:46:57 2016 +0300 @@ -273,7 +273,6 @@ PyObject * PyByteArray_Concat(PyObject *a, PyObject *b) { - Py_ssize_t size; Py_buffer va, vb; PyByteArrayObject *result = NULL; @@ -286,13 +285,13 @@ goto done; } - size = va.len + vb.len; - if (size < 0) { - PyErr_NoMemory(); - goto done; + if (va.len > PY_SSIZE_T_MAX - vb.len) { + PyErr_NoMemory(); + goto done; } - result = (PyByteArrayObject *) PyByteArray_FromStringAndSize(NULL, size); + result = (PyByteArrayObject *) \ + PyByteArray_FromStringAndSize(NULL, va.len + vb.len); if (result != NULL) { memcpy(result->ob_bytes, va.buf, va.len); memcpy(result->ob_bytes + va.len, vb.buf, vb.len); @@ -328,11 +327,11 @@ } mysize = Py_SIZE(self); - size = mysize + vo.len; - if (size < 0) { + if (mysize > PY_SSIZE_T_MAX - vo.len) { PyBuffer_Release(&vo); return PyErr_NoMemory(); } + size = mysize + vo.len; if (size < self->ob_alloc) { Py_SIZE(self) = size; self->ob_bytes[Py_SIZE(self)] = '\0'; /* Trailing null byte */ @@ -357,9 +356,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 +381,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 */ diff -r f7f0f1aecbfa -r 130d97217e36 Objects/stringobject.c --- a/Objects/stringobject.c Mon Jul 11 07:51:37 2016 +0000 +++ b/Objects/stringobject.c Tue Jul 12 15:46:57 2016 +0300 @@ -1040,7 +1040,6 @@ Py_INCREF(a); return (PyObject *)a; } - size = Py_SIZE(a) + Py_SIZE(b); /* Check that string sizes are not negative, to prevent an overflow in cases where we are passed incorrectly-created strings with negative lengths (due to a bug in other code). @@ -1051,6 +1050,7 @@ "strings are too large to concat"); return NULL; } + size = Py_SIZE(a) + Py_SIZE(b); /* Inline PyObject_NewVar */ if (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) { @@ -1081,15 +1081,15 @@ size_t nbytes; if (n < 0) n = 0; - /* watch out for overflows: the size can overflow int, + /* watch out for overflows: the size can overflow Py_ssize_t, * and the # of bytes needed can overflow size_t */ - size = Py_SIZE(a) * n; - if (n && size / n != Py_SIZE(a)) { + if (n && 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; diff -r f7f0f1aecbfa -r 130d97217e36 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Mon Jul 11 07:51:37 2016 +0000 +++ b/Objects/unicodeobject.c Tue Jul 12 15:46:57 2016 +0300 @@ -6378,6 +6378,12 @@ return (PyObject *)v; } + if (u->length > PY_SSIZE_T_MAX - v->length) { + PyErr_SetString(PyExc_OverflowError, + "strings are too large to concat"); + goto onError; + } + /* Concat the two Unicode strings */ w = _PyUnicode_New(u->length + v->length); if (w == NULL) @@ -7223,17 +7229,17 @@ return (PyObject*) str; } - /* ensure # of chars needed doesn't overflow int and # of bytes + /* ensure # of chars needed doesn't overflow Py_ssize_t 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; + nbytes = ((size_t)nchars + 1u) * sizeof(Py_UNICODE); + if (nbytes / sizeof(Py_UNICODE) != ((size_t)nchars + 1u)) { PyErr_SetString(PyExc_OverflowError, "repeated string is too long"); return NULL;