]> granicus.if.org Git - python/commitdiff
Issue #27473: Fixed possible integer overflow in str, unicode and bytearray
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 12 Jul 2016 12:46:57 +0000 (15:46 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 12 Jul 2016 12:46:57 +0000 (15:46 +0300)
concatenations and repetitions.  Based on patch by Xiang Zhang.

Misc/NEWS
Objects/bytearrayobject.c
Objects/stringobject.c
Objects/unicodeobject.c

index 023f46a3cbf5af4b90af1fd0bbb3fedd07578d8e..1623242050540361a419c95e9f6a9f49aba220fa 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 2.7.13?
 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.
index a90bdebb162c1c3dfa317397f6b168ad68ae66e4..bf8a74eef9d539986d06b62d929152188c320850 100644 (file)
@@ -273,7 +273,6 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
 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 *b)
             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 *self, PyObject *other)
     }
 
     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, Py_ssize_t count)
     if (count < 0)
         count = 0;
     mysize = Py_SIZE(self);
-    size = mysize * count;
-    if (count != 0 && size / count != mysize)
+    if (count != 0 && mysize > PY_SSIZE_T_MAX / count)
         return PyErr_NoMemory();
+    size = mysize * count;
     result = (PyByteArrayObject *)PyByteArray_FromStringAndSize(NULL, size);
     if (result != NULL && size != 0) {
         if (mysize == 1)
@@ -382,9 +381,9 @@ bytearray_irepeat(PyByteArrayObject *self, Py_ssize_t count)
     if (count < 0)
         count = 0;
     mysize = Py_SIZE(self);
-    size = mysize * count;
-    if (count != 0 && size / count != mysize)
+    if (count != 0 && mysize > PY_SSIZE_T_MAX / count)
         return PyErr_NoMemory();
+    size = mysize * count;
     if (size < self->ob_alloc) {
         Py_SIZE(self) = size;
         self->ob_bytes[Py_SIZE(self)] = '\0'; /* Trailing null byte */
index 1a04b787b3b79193d42b0c2664aa6f64352f0272..342b2dbded28182ce10b3ddfe68fde5fc17f79cf 100644 (file)
@@ -1040,7 +1040,6 @@ string_concat(register PyStringObject *a, register PyObject *bb)
         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, register PyObject *bb)
                         "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, register Py_ssize_t n)
     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;
index ca6628e2eaf7a98f25ce99e889db43fb51bab901..151ce3c5584461ecdc37ba461fd45ba718e10568 100644 (file)
@@ -6378,6 +6378,12 @@ PyObject *PyUnicode_Concat(PyObject *left,
         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 @@ unicode_repeat(PyUnicodeObject *str, Py_ssize_t len)
         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;