diff -r c613d8885054 Misc/NEWS --- a/Misc/NEWS Sun Jul 10 08:34:21 2016 -0700 +++ b/Misc/NEWS Sun Jul 10 22:02:25 2016 +0300 @@ -10,6 +10,9 @@ What's New in Python 2.7.13? Core and Builtins ----------------- +- Issue #27473: Fixed possible integer overflow in bytes and bytearray + concatenations. 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 truncate them. diff -r c613d8885054 Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Sun Jul 10 08:34:21 2016 -0700 +++ b/Objects/bytearrayobject.c Sun Jul 10 22:02:25 2016 +0300 @@ -273,7 +273,6 @@ PyByteArray_Resize(PyObject *self, Py_ss PyObject * PyByteArray_Concat(PyObject *a, PyObject *b) { - Py_ssize_t size; Py_buffer va, vb; PyByteArrayObject *result = NULL; @@ -286,13 +285,13 @@ PyByteArray_Concat(PyObject *a, PyObject 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 @@ bytearray_iconcat(PyByteArrayObject *sel } 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 @@ bytearray_repeat(PyByteArrayObject *self 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 @@ bytearray_irepeat(PyByteArrayObject *sel 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 c613d8885054 Objects/stringobject.c --- a/Objects/stringobject.c Sun Jul 10 08:34:21 2016 -0700 +++ b/Objects/stringobject.c Sun Jul 10 22:02:25 2016 +0300 @@ -1040,7 +1040,6 @@ string_concat(register PyStringObject *a 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 @@ string_concat(register PyStringObject *a "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 @@ string_repeat(register PyStringObject *a 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 c613d8885054 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Sun Jul 10 08:34:21 2016 -0700 +++ b/Objects/unicodeobject.c Sun Jul 10 22:02:25 2016 +0300 @@ -6378,6 +6378,12 @@ PyObject *PyUnicode_Concat(PyObject *lef 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) @@ -7212,7 +7218,6 @@ unicode_repeat(PyUnicodeObject *str, Py_ PyUnicodeObject *u; Py_UNICODE *p; Py_ssize_t nchars; - size_t nbytes; if (len < 0) len = 0; @@ -7223,17 +7228,16 @@ unicode_repeat(PyUnicodeObject *str, Py_ 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; + if (nchars > SIZE_MAX / sizeof(Py_UNICODE) - 1) { PyErr_SetString(PyExc_OverflowError, "repeated string is too long"); return NULL;