Skip to content

Commit 8a03896

Browse files
committed
Issue python#22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff bytes on a 32-bit platform.
2 parents c58e3a4 + cc23154 commit 8a03896

4 files changed

Lines changed: 34 additions & 11 deletions

File tree

Lib/test/test_bytes.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
import pickle
1414
import tempfile
1515
import unittest
16+
1617
import test.support
1718
import test.string_tests
1819
import test.buffer_tests
20+
from test.support import bigaddrspacetest, MAX_Py_ssize_t
1921

2022

2123
if sys.flags.bytes_warning:
@@ -111,6 +113,17 @@ def test_constructor_value_errors(self):
111113
self.assertRaises(ValueError, self.type2test, [sys.maxsize+1])
112114
self.assertRaises(ValueError, self.type2test, [10**100])
113115

116+
@bigaddrspacetest
117+
def test_constructor_overflow(self):
118+
size = MAX_Py_ssize_t
119+
self.assertRaises((OverflowError, MemoryError), self.type2test, size)
120+
try:
121+
# Should either pass or raise an error (e.g. on debug builds with
122+
# additional malloc() overhead), but shouldn't crash.
123+
bytearray(size - 4)
124+
except (OverflowError, MemoryError):
125+
pass
126+
114127
def test_compare(self):
115128
b1 = self.type2test([1, 2, 3])
116129
b2 = self.type2test([1, 2, 3])

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Release date: TBA
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff
14+
bytes on a 32-bit platform.
15+
1316
- Issue #22653: Fix an assertion failure in debug mode when doing a reentrant
1417
dict insertion in debug mode.
1518

Objects/bytearrayobject.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,22 @@ PyByteArray_AsString(PyObject *self)
180180
}
181181

182182
int
183-
PyByteArray_Resize(PyObject *self, Py_ssize_t size)
183+
PyByteArray_Resize(PyObject *self, Py_ssize_t requested_size)
184184
{
185185
void *sval;
186186
PyByteArrayObject *obj = ((PyByteArrayObject *)self);
187-
Py_ssize_t alloc = obj->ob_alloc;
188-
Py_ssize_t logical_offset = obj->ob_start - obj->ob_bytes;
187+
/* All computations are done unsigned to avoid integer overflows
188+
(see issue #22335). */
189+
size_t alloc = (size_t) obj->ob_alloc;
190+
size_t logical_offset = (size_t) (obj->ob_start - obj->ob_bytes);
191+
size_t size = (size_t) requested_size;
189192

190193
assert(self != NULL);
191194
assert(PyByteArray_Check(self));
192-
assert(size >= 0);
193-
assert(logical_offset >= 0);
194195
assert(logical_offset <= alloc);
196+
assert(requested_size >= 0);
195197

196-
if (size == Py_SIZE(self)) {
198+
if (requested_size == Py_SIZE(self)) {
197199
return 0;
198200
}
199201
if (!_canresize(obj)) {
@@ -225,14 +227,19 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
225227
alloc = size + 1;
226228
}
227229
}
230+
if (alloc > PY_SSIZE_T_MAX) {
231+
PyErr_NoMemory();
232+
return -1;
233+
}
228234

229235
if (logical_offset > 0) {
230236
sval = PyObject_Malloc(alloc);
231237
if (sval == NULL) {
232238
PyErr_NoMemory();
233239
return -1;
234240
}
235-
memcpy(sval, PyByteArray_AS_STRING(self), Py_MIN(size, Py_SIZE(self)));
241+
memcpy(sval, PyByteArray_AS_STRING(self),
242+
Py_MIN(requested_size, Py_SIZE(self)));
236243
PyObject_Free(obj->ob_bytes);
237244
}
238245
else {

Objects/obmalloc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,8 +1828,8 @@ _PyMem_DebugAlloc(int use_calloc, void *ctx, size_t nbytes)
18281828

18291829
bumpserialno();
18301830
total = nbytes + 4*SST;
1831-
if (total < nbytes)
1832-
/* overflow: can't represent total as a size_t */
1831+
if (nbytes > PY_SSIZE_T_MAX - 4*SST)
1832+
/* overflow: can't represent total as a Py_ssize_t */
18331833
return NULL;
18341834

18351835
if (use_calloc)
@@ -1909,8 +1909,8 @@ _PyMem_DebugRealloc(void *ctx, void *p, size_t nbytes)
19091909
bumpserialno();
19101910
original_nbytes = read_size_t(q - 2*SST);
19111911
total = nbytes + 4*SST;
1912-
if (total < nbytes)
1913-
/* overflow: can't represent total as a size_t */
1912+
if (nbytes > PY_SSIZE_T_MAX - 4*SST)
1913+
/* overflow: can't represent total as a Py_ssize_t */
19141914
return NULL;
19151915

19161916
/* Resize and add decorations. We may get a new pointer here, in which

0 commit comments

Comments
 (0)