Skip to content

Commit 373773d

Browse files
Issue #27473: Fixed possible integer overflow in str, unicode and bytearray
concatenations and repetitions. Based on patch by Xiang Zhang.
1 parent bf2dca9 commit 373773d

File tree

4 files changed

+29
-21
lines changed

4 files changed

+29
-21
lines changed

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 2.7.13?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #27473: Fixed possible integer overflow in str, unicode and bytearray
14+
concatenations and repetitions. Based on patch by Xiang Zhang.
15+
1316
- Issue #23908: os functions, open() and the io.FileIO constructor now reject
1417
unicode paths with embedded null character on Windows instead of silently
1518
truncating them.

Objects/bytearrayobject.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
273273
PyObject *
274274
PyByteArray_Concat(PyObject *a, PyObject *b)
275275
{
276-
Py_ssize_t size;
277276
Py_buffer va, vb;
278277
PyByteArrayObject *result = NULL;
279278

@@ -286,13 +285,13 @@ PyByteArray_Concat(PyObject *a, PyObject *b)
286285
goto done;
287286
}
288287

289-
size = va.len + vb.len;
290-
if (size < 0) {
291-
PyErr_NoMemory();
292-
goto done;
288+
if (va.len > PY_SSIZE_T_MAX - vb.len) {
289+
PyErr_NoMemory();
290+
goto done;
293291
}
294292

295-
result = (PyByteArrayObject *) PyByteArray_FromStringAndSize(NULL, size);
293+
result = (PyByteArrayObject *) \
294+
PyByteArray_FromStringAndSize(NULL, va.len + vb.len);
296295
if (result != NULL) {
297296
memcpy(result->ob_bytes, va.buf, va.len);
298297
memcpy(result->ob_bytes + va.len, vb.buf, vb.len);
@@ -328,11 +327,11 @@ bytearray_iconcat(PyByteArrayObject *self, PyObject *other)
328327
}
329328

330329
mysize = Py_SIZE(self);
331-
size = mysize + vo.len;
332-
if (size < 0) {
330+
if (mysize > PY_SSIZE_T_MAX - vo.len) {
333331
PyBuffer_Release(&vo);
334332
return PyErr_NoMemory();
335333
}
334+
size = mysize + vo.len;
336335
if (size < self->ob_alloc) {
337336
Py_SIZE(self) = size;
338337
self->ob_bytes[Py_SIZE(self)] = '\0'; /* Trailing null byte */
@@ -357,9 +356,9 @@ bytearray_repeat(PyByteArrayObject *self, Py_ssize_t count)
357356
if (count < 0)
358357
count = 0;
359358
mysize = Py_SIZE(self);
360-
size = mysize * count;
361-
if (count != 0 && size / count != mysize)
359+
if (count != 0 && mysize > PY_SSIZE_T_MAX / count)
362360
return PyErr_NoMemory();
361+
size = mysize * count;
363362
result = (PyByteArrayObject *)PyByteArray_FromStringAndSize(NULL, size);
364363
if (result != NULL && size != 0) {
365364
if (mysize == 1)
@@ -382,9 +381,9 @@ bytearray_irepeat(PyByteArrayObject *self, Py_ssize_t count)
382381
if (count < 0)
383382
count = 0;
384383
mysize = Py_SIZE(self);
385-
size = mysize * count;
386-
if (count != 0 && size / count != mysize)
384+
if (count != 0 && mysize > PY_SSIZE_T_MAX / count)
387385
return PyErr_NoMemory();
386+
size = mysize * count;
388387
if (size < self->ob_alloc) {
389388
Py_SIZE(self) = size;
390389
self->ob_bytes[Py_SIZE(self)] = '\0'; /* Trailing null byte */

Objects/stringobject.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,6 @@ string_concat(register PyStringObject *a, register PyObject *bb)
10401040
Py_INCREF(a);
10411041
return (PyObject *)a;
10421042
}
1043-
size = Py_SIZE(a) + Py_SIZE(b);
10441043
/* Check that string sizes are not negative, to prevent an
10451044
overflow in cases where we are passed incorrectly-created
10461045
strings with negative lengths (due to a bug in other code).
@@ -1051,6 +1050,7 @@ string_concat(register PyStringObject *a, register PyObject *bb)
10511050
"strings are too large to concat");
10521051
return NULL;
10531052
}
1053+
size = Py_SIZE(a) + Py_SIZE(b);
10541054

10551055
/* Inline PyObject_NewVar */
10561056
if (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) {
@@ -1081,15 +1081,15 @@ string_repeat(register PyStringObject *a, register Py_ssize_t n)
10811081
size_t nbytes;
10821082
if (n < 0)
10831083
n = 0;
1084-
/* watch out for overflows: the size can overflow int,
1084+
/* watch out for overflows: the size can overflow Py_ssize_t,
10851085
* and the # of bytes needed can overflow size_t
10861086
*/
1087-
size = Py_SIZE(a) * n;
1088-
if (n && size / n != Py_SIZE(a)) {
1087+
if (n && Py_SIZE(a) > PY_SSIZE_T_MAX / n) {
10891088
PyErr_SetString(PyExc_OverflowError,
10901089
"repeated string is too long");
10911090
return NULL;
10921091
}
1092+
size = Py_SIZE(a) * n;
10931093
if (size == Py_SIZE(a) && PyString_CheckExact(a)) {
10941094
Py_INCREF(a);
10951095
return (PyObject *)a;

Objects/unicodeobject.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6378,6 +6378,12 @@ PyObject *PyUnicode_Concat(PyObject *left,
63786378
return (PyObject *)v;
63796379
}
63806380

6381+
if (u->length > PY_SSIZE_T_MAX - v->length) {
6382+
PyErr_SetString(PyExc_OverflowError,
6383+
"strings are too large to concat");
6384+
goto onError;
6385+
}
6386+
63816387
/* Concat the two Unicode strings */
63826388
w = _PyUnicode_New(u->length + v->length);
63836389
if (w == NULL)
@@ -7223,17 +7229,17 @@ unicode_repeat(PyUnicodeObject *str, Py_ssize_t len)
72237229
return (PyObject*) str;
72247230
}
72257231

7226-
/* ensure # of chars needed doesn't overflow int and # of bytes
7232+
/* ensure # of chars needed doesn't overflow Py_ssize_t and # of bytes
72277233
* needed doesn't overflow size_t
72287234
*/
7229-
nchars = len * str->length;
7230-
if (len && nchars / len != str->length) {
7235+
if (len && str->length > PY_SSIZE_T_MAX / len) {
72317236
PyErr_SetString(PyExc_OverflowError,
72327237
"repeated string is too long");
72337238
return NULL;
72347239
}
7235-
nbytes = (nchars + 1) * sizeof(Py_UNICODE);
7236-
if (nbytes / sizeof(Py_UNICODE) != (size_t)(nchars + 1)) {
7240+
nchars = len * str->length;
7241+
nbytes = ((size_t)nchars + 1u) * sizeof(Py_UNICODE);
7242+
if (nbytes / sizeof(Py_UNICODE) != ((size_t)nchars + 1u)) {
72377243
PyErr_SetString(PyExc_OverflowError,
72387244
"repeated string is too long");
72397245
return NULL;

0 commit comments

Comments
 (0)