]> granicus.if.org Git - python/commitdiff
Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff bytes on...
authorAntoine Pitrou <solipsis@pitrou.net>
Sun, 2 Nov 2014 17:40:09 +0000 (18:40 +0100)
committerAntoine Pitrou <solipsis@pitrou.net>
Sun, 2 Nov 2014 17:40:09 +0000 (18:40 +0100)
Lib/test/test_bytes.py
Misc/NEWS
Objects/bytearrayobject.c
Objects/obmalloc.c

index 1a351a53725d106303c7963081275e525e863e1a..0177749e212d94e6ac611dc1431a055056e3e691 100644 (file)
@@ -13,9 +13,11 @@ import functools
 import pickle
 import tempfile
 import unittest
+
 import test.support
 import test.string_tests
 import test.buffer_tests
+from test.support import bigaddrspacetest, MAX_Py_ssize_t
 
 
 if sys.flags.bytes_warning:
@@ -111,6 +113,17 @@ class BaseBytesTest:
         self.assertRaises(ValueError, self.type2test, [sys.maxsize+1])
         self.assertRaises(ValueError, self.type2test, [10**100])
 
+    @bigaddrspacetest
+    def test_constructor_overflow(self):
+        size = MAX_Py_ssize_t
+        self.assertRaises((OverflowError, MemoryError), self.type2test, size)
+        try:
+            # Should either pass or raise an error (e.g. on debug builds with
+            # additional malloc() overhead), but shouldn't crash.
+            bytearray(size - 4)
+        except (OverflowError, MemoryError):
+            pass
+
     def test_compare(self):
         b1 = self.type2test([1, 2, 3])
         b2 = self.type2test([1, 2, 3])
index 8a5ca30861225c301c720220de4bc7df8fba6c9e..e2a7d73496fe3dda1b6a31dd4d6fd2fe878b32e2 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -11,6 +11,9 @@ Release date: TBA
 Core and Builtins
 -----------------
 
+- Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff
+  bytes on a 32-bit platform.
+
 - Issue #22653: Fix an assertion failure in debug mode when doing a reentrant
   dict insertion in debug mode.
 
index 5b75705abff138cb0a91e3d6f699abff9dc919be..d72abb7bb23fdb2b79b3d381329aa567c96e2332 100644 (file)
@@ -175,20 +175,22 @@ PyByteArray_AsString(PyObject *self)
 }
 
 int
-PyByteArray_Resize(PyObject *self, Py_ssize_t size)
+PyByteArray_Resize(PyObject *self, Py_ssize_t requested_size)
 {
     void *sval;
     PyByteArrayObject *obj = ((PyByteArrayObject *)self);
-    Py_ssize_t alloc = obj->ob_alloc;
-    Py_ssize_t logical_offset = obj->ob_start - obj->ob_bytes;
+    /* All computations are done unsigned to avoid integer overflows
+       (see issue #22335). */
+    size_t alloc = (size_t) obj->ob_alloc;
+    size_t logical_offset = (size_t) (obj->ob_start - obj->ob_bytes);
+    size_t size = (size_t) requested_size;
 
     assert(self != NULL);
     assert(PyByteArray_Check(self));
-    assert(size >= 0);
-    assert(logical_offset >= 0);
     assert(logical_offset <= alloc);
+    assert(requested_size >= 0);
 
-    if (size == Py_SIZE(self)) {
+    if (requested_size == Py_SIZE(self)) {
         return 0;
     }
     if (!_canresize(obj)) {
@@ -220,6 +222,10 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
             alloc = size + 1;
         }
     }
+    if (alloc > PY_SSIZE_T_MAX) {
+        PyErr_NoMemory();
+        return -1;
+    }
 
     if (logical_offset > 0) {
         sval = PyObject_Malloc(alloc);
@@ -227,7 +233,8 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
             PyErr_NoMemory();
             return -1;
         }
-        memcpy(sval, PyByteArray_AS_STRING(self), Py_MIN(size, Py_SIZE(self)));
+        memcpy(sval, PyByteArray_AS_STRING(self),
+               Py_MIN(requested_size, Py_SIZE(self)));
         PyObject_Free(obj->ob_bytes);
     }
     else {
index 004cfaac61742ab443fb18d76d99b433f9b708c8..3c33255170279b409d7ae2cb30fbdfcd2f90df41 100644 (file)
@@ -1754,8 +1754,8 @@ _PyMem_DebugMalloc(void *ctx, size_t nbytes)
 
     bumpserialno();
     total = nbytes + 4*SST;
-    if (total < nbytes)
-        /* overflow:  can't represent total as a size_t */
+    if (nbytes > PY_SSIZE_T_MAX - 4*SST)
+        /* overflow:  can't represent total as a Py_ssize_t */
         return NULL;
 
     p = (uchar *)api->alloc.malloc(api->alloc.ctx, total);
@@ -1817,8 +1817,8 @@ _PyMem_DebugRealloc(void *ctx, void *p, size_t nbytes)
     bumpserialno();
     original_nbytes = read_size_t(q - 2*SST);
     total = nbytes + 4*SST;
-    if (total < nbytes)
-        /* overflow:  can't represent total as a size_t */
+    if (nbytes > PY_SSIZE_T_MAX - 4*SST)
+        /* overflow:  can't represent total as a Py_ssize_t */
         return NULL;
 
     /* Resize and add decorations. We may get a new pointer here, in which