Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7bdb516

Browse files
committed
Issue python#29145: Fix overflow checks in string, bytearray and unicode.
Patch by jan matejek and Xiang Zhang.
1 parent 10434d6 commit 7bdb516

4 files changed

Lines changed: 54 additions & 74 deletions

File tree

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.14?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #29145: Fix overflow checks in string, bytearray and unicode.
14+
Patch by jan matejek and Xiang Zhang.
15+
1316
- Issue #28932: Do not include <sys/random.h> if it does not exist.
1417

1518
Extension Modules

Objects/bytearrayobject.c

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,31 +1571,30 @@ replace_interleave(PyByteArrayObject *self,
15711571
{
15721572
char *self_s, *result_s;
15731573
Py_ssize_t self_len, result_len;
1574-
Py_ssize_t count, i, product;
1574+
Py_ssize_t count, i;
15751575
PyByteArrayObject *result;
15761576

15771577
self_len = PyByteArray_GET_SIZE(self);
15781578

1579-
/* 1 at the end plus 1 after every character */
1580-
count = self_len+1;
1581-
if (maxcount < count)
1579+
/* 1 at the end plus 1 after every character;
1580+
count = min(maxcount, self_len + 1) */
1581+
if (maxcount <= self_len) {
15821582
count = maxcount;
1583+
}
1584+
else {
1585+
/* Can't overflow: self_len + 1 <= maxcount <= PY_SSIZE_T_MAX. */
1586+
count = self_len + 1;
1587+
}
15831588

15841589
/* Check for overflow */
15851590
/* result_len = count * to_len + self_len; */
1586-
product = count * to_len;
1587-
if (product / to_len != count) {
1591+
assert(count > 0);
1592+
if (to_len > (PY_SSIZE_T_MAX - self_len) / count) {
15881593
PyErr_SetString(PyExc_OverflowError,
1589-
"replace string is too long");
1594+
"replace bytes is too long");
15901595
return NULL;
15911596
}
1592-
result_len = product + self_len;
1593-
if (result_len < 0) {
1594-
PyErr_SetString(PyExc_OverflowError,
1595-
"replace string is too long");
1596-
return NULL;
1597-
}
1598-
1597+
result_len = count * to_len + self_len;
15991598
if (! (result = (PyByteArrayObject *)
16001599
PyByteArray_FromStringAndSize(NULL, result_len)) )
16011600
return NULL;
@@ -1824,7 +1823,7 @@ replace_single_character(PyByteArrayObject *self,
18241823
char *self_s, *result_s;
18251824
char *start, *next, *end;
18261825
Py_ssize_t self_len, result_len;
1827-
Py_ssize_t count, product;
1826+
Py_ssize_t count;
18281827
PyByteArrayObject *result;
18291828

18301829
self_s = PyByteArray_AS_STRING(self);
@@ -1838,16 +1837,12 @@ replace_single_character(PyByteArrayObject *self,
18381837

18391838
/* use the difference between current and new, hence the "-1" */
18401839
/* result_len = self_len + count * (to_len-1) */
1841-
product = count * (to_len-1);
1842-
if (product / (to_len-1) != count) {
1840+
assert(count > 0);
1841+
if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) {
18431842
PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
18441843
return NULL;
18451844
}
1846-
result_len = self_len + product;
1847-
if (result_len < 0) {
1848-
PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
1849-
return NULL;
1850-
}
1845+
result_len = self_len + count * (to_len - 1);
18511846

18521847
if ( (result = (PyByteArrayObject *)
18531848
PyByteArray_FromStringAndSize(NULL, result_len)) == NULL)
@@ -1891,7 +1886,7 @@ replace_substring(PyByteArrayObject *self,
18911886
char *self_s, *result_s;
18921887
char *start, *next, *end;
18931888
Py_ssize_t self_len, result_len;
1894-
Py_ssize_t count, offset, product;
1889+
Py_ssize_t count, offset;
18951890
PyByteArrayObject *result;
18961891

18971892
self_s = PyByteArray_AS_STRING(self);
@@ -1908,16 +1903,12 @@ replace_substring(PyByteArrayObject *self,
19081903

19091904
/* Check for overflow */
19101905
/* result_len = self_len + count * (to_len-from_len) */
1911-
product = count * (to_len-from_len);
1912-
if (product / (to_len-from_len) != count) {
1913-
PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
1914-
return NULL;
1915-
}
1916-
result_len = self_len + product;
1917-
if (result_len < 0) {
1906+
assert(count > 0);
1907+
if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) {
19181908
PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
19191909
return NULL;
19201910
}
1911+
result_len = self_len + count * (to_len - from_len);
19211912

19221913
if ( (result = (PyByteArrayObject *)
19231914
PyByteArray_FromStringAndSize(NULL, result_len)) == NULL)

Objects/stringobject.c

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,31 +2358,30 @@ replace_interleave(PyStringObject *self,
23582358
{
23592359
char *self_s, *result_s;
23602360
Py_ssize_t self_len, result_len;
2361-
Py_ssize_t count, i, product;
2361+
Py_ssize_t count, i;
23622362
PyStringObject *result;
23632363

23642364
self_len = PyString_GET_SIZE(self);
23652365

2366-
/* 1 at the end plus 1 after every character */
2367-
count = self_len+1;
2368-
if (maxcount < count)
2366+
/* 1 at the end plus 1 after every character;
2367+
count = min(maxcount, self_len + 1) */
2368+
if (maxcount <= self_len) {
23692369
count = maxcount;
2370+
}
2371+
else {
2372+
/* Can't overflow: self_len + 1 <= maxcount <= PY_SSIZE_T_MAX. */
2373+
count = self_len + 1;
2374+
}
23702375

23712376
/* Check for overflow */
23722377
/* result_len = count * to_len + self_len; */
2373-
product = count * to_len;
2374-
if (product / to_len != count) {
2375-
PyErr_SetString(PyExc_OverflowError,
2376-
"replace string is too long");
2377-
return NULL;
2378-
}
2379-
result_len = product + self_len;
2380-
if (result_len < 0) {
2378+
assert(count > 0);
2379+
if (to_len > (PY_SSIZE_T_MAX - self_len) / count) {
23812380
PyErr_SetString(PyExc_OverflowError,
23822381
"replace string is too long");
23832382
return NULL;
23842383
}
2385-
2384+
result_len = count * to_len + self_len;
23862385
if (! (result = (PyStringObject *)
23872386
PyString_FromStringAndSize(NULL, result_len)) )
23882387
return NULL;
@@ -2610,7 +2609,7 @@ replace_single_character(PyStringObject *self,
26102609
char *self_s, *result_s;
26112610
char *start, *next, *end;
26122611
Py_ssize_t self_len, result_len;
2613-
Py_ssize_t count, product;
2612+
Py_ssize_t count;
26142613
PyStringObject *result;
26152614

26162615
self_s = PyString_AS_STRING(self);
@@ -2624,16 +2623,12 @@ replace_single_character(PyStringObject *self,
26242623

26252624
/* use the difference between current and new, hence the "-1" */
26262625
/* result_len = self_len + count * (to_len-1) */
2627-
product = count * (to_len-1);
2628-
if (product / (to_len-1) != count) {
2629-
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
2630-
return NULL;
2631-
}
2632-
result_len = self_len + product;
2633-
if (result_len < 0) {
2626+
assert(count > 0);
2627+
if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) {
26342628
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
26352629
return NULL;
26362630
}
2631+
result_len = self_len + count * (to_len - 1);
26372632

26382633
if ( (result = (PyStringObject *)
26392634
PyString_FromStringAndSize(NULL, result_len)) == NULL)
@@ -2676,7 +2671,7 @@ replace_substring(PyStringObject *self,
26762671
char *self_s, *result_s;
26772672
char *start, *next, *end;
26782673
Py_ssize_t self_len, result_len;
2679-
Py_ssize_t count, offset, product;
2674+
Py_ssize_t count, offset;
26802675
PyStringObject *result;
26812676

26822677
self_s = PyString_AS_STRING(self);
@@ -2693,16 +2688,12 @@ replace_substring(PyStringObject *self,
26932688

26942689
/* Check for overflow */
26952690
/* result_len = self_len + count * (to_len-from_len) */
2696-
product = count * (to_len-from_len);
2697-
if (product / (to_len-from_len) != count) {
2698-
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
2699-
return NULL;
2700-
}
2701-
result_len = self_len + product;
2702-
if (result_len < 0) {
2691+
assert(count > 0);
2692+
if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) {
27032693
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
27042694
return NULL;
27052695
}
2696+
result_len = self_len + count * (to_len - from_len);
27062697

27072698
if ( (result = (PyStringObject *)
27082699
PyString_FromStringAndSize(NULL, result_len)) == NULL)

Objects/unicodeobject.c

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5732,20 +5732,20 @@ PyUnicode_Join(PyObject *separator, PyObject *seq)
57325732

57335733
/* Make sure we have enough space for the separator and the item. */
57345734
itemlen = PyUnicode_GET_SIZE(item);
5735-
new_res_used = res_used + itemlen;
5736-
if (new_res_used < 0)
5735+
if (res_used > PY_SSIZE_T_MAX - itemlen)
57375736
goto Overflow;
5737+
new_res_used = res_used + itemlen;
57385738
if (i < seqlen - 1) {
5739-
new_res_used += seplen;
5740-
if (new_res_used < 0)
5739+
if (new_res_used > PY_SSIZE_T_MAX - seplen)
57415740
goto Overflow;
5741+
new_res_used += seplen;
57425742
}
57435743
if (new_res_used > res_alloc) {
57445744
/* double allocated size until it's big enough */
57455745
do {
5746-
res_alloc += res_alloc;
5747-
if (res_alloc <= 0)
5746+
if (res_alloc > PY_SSIZE_T_MAX / 2)
57485747
goto Overflow;
5748+
res_alloc += res_alloc;
57495749
} while (new_res_used > res_alloc);
57505750
if (_PyUnicode_Resize(&res, res_alloc) < 0) {
57515751
Py_DECREF(item);
@@ -5943,7 +5943,7 @@ PyObject *replace(PyUnicodeObject *self,
59435943
} else {
59445944

59455945
Py_ssize_t n, i, j;
5946-
Py_ssize_t product, new_size, delta;
5946+
Py_ssize_t new_size, delta;
59475947
Py_UNICODE *p;
59485948

59495949
/* replace strings */
@@ -5956,18 +5956,13 @@ PyObject *replace(PyUnicodeObject *self,
59565956
if (delta == 0) {
59575957
new_size = self->length;
59585958
} else {
5959-
product = n * (str2->length - str1->length);
5960-
if ((product / (str2->length - str1->length)) != n) {
5961-
PyErr_SetString(PyExc_OverflowError,
5962-
"replace string is too long");
5963-
return NULL;
5964-
}
5965-
new_size = self->length + product;
5966-
if (new_size < 0) {
5959+
assert(n > 0);
5960+
if (delta > (PY_SSIZE_T_MAX - self->length) / n) {
59675961
PyErr_SetString(PyExc_OverflowError,
59685962
"replace string is too long");
59695963
return NULL;
59705964
}
5965+
new_size = self->length + delta * n;
59715966
}
59725967
u = _PyUnicode_New(new_size);
59735968
if (!u)

0 commit comments

Comments
 (0)