Skip to content

Commit 05a25bb

Browse files
author
gregory.p.smith
committed
Merge in release25-maint r60793:
Added checks for integer overflows, contributed by Google. Some are only available if asserts are left in the code, in cases where they can't be triggered from Python code. git-svn-id: http://svn.python.org/projects/python/trunk@64114 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent ecfeaf4 commit 05a25bb

File tree

24 files changed

+438
-54
lines changed

24 files changed

+438
-54
lines changed

Include/pymem.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,18 @@ PyAPI_FUNC(void) PyMem_Free(void *);
8585
*/
8686

8787
#define PyMem_New(type, n) \
88-
( (type *) PyMem_Malloc((n) * sizeof(type)) )
88+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
89+
( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
8990
#define PyMem_NEW(type, n) \
90-
( (type *) PyMem_MALLOC((n) * sizeof(type)) )
91+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
92+
( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
9193

9294
#define PyMem_Resize(p, type, n) \
93-
( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
95+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
96+
( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) )
9497
#define PyMem_RESIZE(p, type, n) \
95-
( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
98+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
99+
( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) )
96100

97101
/* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used
98102
* anymore. They're just confusing aliases for PyMem_{Free,FREE} now.

Include/pyport.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ typedef Py_intptr_t Py_ssize_t;
117117
# error "Python needs a typedef for Py_ssize_t in pyport.h."
118118
#endif
119119

120+
/* Largest possible value of size_t.
121+
SIZE_MAX is part of C99, so it might be defined on some
122+
platforms. If it is not defined, (size_t)-1 is a portable
123+
definition for C89, due to the way signed->unsigned
124+
conversion is defined. */
125+
#ifdef SIZE_MAX
126+
#define PY_SIZE_MAX SIZE_MAX
127+
#else
128+
#define PY_SIZE_MAX ((size_t)-1)
129+
#endif
130+
120131
/* Largest positive value of type Py_ssize_t. */
121132
#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1))
122133
/* Smallest negative value of type Py_ssize_t. */

Lib/test/test_array.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,23 @@ class FloatTest(FPTest):
10091009
class DoubleTest(FPTest):
10101010
typecode = 'd'
10111011
minitemsize = 8
1012+
1013+
def test_alloc_overflow(self):
1014+
a = array.array('d', [-1]*65536)
1015+
try:
1016+
a *= 65536
1017+
except MemoryError:
1018+
pass
1019+
else:
1020+
self.fail("a *= 2**16 didn't raise MemoryError")
1021+
b = array.array('d', [ 2.71828183, 3.14159265, -1])
1022+
try:
1023+
b * 1431655766
1024+
except MemoryError:
1025+
pass
1026+
else:
1027+
self.fail("a * 1431655766 didn't raise MemoryError")
1028+
10121029
tests.append(DoubleTest)
10131030

10141031
def test_main(verbose=None):

Lib/test/test_struct.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import sys
1010
ISBIGENDIAN = sys.byteorder == "big"
11+
IS32BIT = sys.maxint == 0x7fffffff
1112
del sys
1213

1314
try:
@@ -568,6 +569,13 @@ def test_bool(self):
568569
for c in '\x01\x7f\xff\x0f\xf0':
569570
self.assertTrue(struct.unpack('>?', c)[0])
570571

572+
def test_crasher(self):
573+
if IS32BIT:
574+
self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
575+
else:
576+
print "%s test_crasher skipped on 64bit build."
577+
578+
571579

572580
def test_main():
573581
run_unittest(StructTest)

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ Core and Builtins
4040
Exception (KeyboardInterrupt, and SystemExit) propagate instead of
4141
ignoring them.
4242

43+
- Added checks for integer overflows, contributed by Google. Some are
44+
only available if asserts are left in the code, in cases where they
45+
can't be triggered from Python code.
46+
47+
4348
Extension Modules
4449
-----------------
4550

Modules/_csv.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,10 @@ parse_grow_buff(ReaderObj *self)
559559
self->field = PyMem_Malloc(self->field_size);
560560
}
561561
else {
562+
if (self->field_size > INT_MAX / 2) {
563+
PyErr_NoMemory();
564+
return 0;
565+
}
562566
self->field_size *= 2;
563567
self->field = PyMem_Realloc(self->field, self->field_size);
564568
}
@@ -1053,6 +1057,12 @@ join_append_data(WriterObj *self, char *field, int quote_empty,
10531057
static int
10541058
join_check_rec_size(WriterObj *self, int rec_len)
10551059
{
1060+
1061+
if (rec_len < 0 || rec_len > INT_MAX - MEM_INCR) {
1062+
PyErr_NoMemory();
1063+
return 0;
1064+
}
1065+
10561066
if (rec_len > self->rec_size) {
10571067
if (self->rec_size == 0) {
10581068
self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;

Modules/_struct.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,12 @@ prepare_s(PyStructObject *self)
13851385
}
13861386
}
13871387

1388+
/* check for overflow */
1389+
if ((len + 1) > (PY_SSIZE_T_MAX / sizeof(formatcode))) {
1390+
PyErr_NoMemory();
1391+
return -1;
1392+
}
1393+
13881394
self->s_size = size;
13891395
self->s_len = len;
13901396
codes = PyMem_MALLOC((len + 1) * sizeof(formatcode));

Modules/arraymodule.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,9 @@ array_concat(arrayobject *a, PyObject *bb)
652652
PyErr_BadArgument();
653653
return NULL;
654654
}
655+
if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b)) {
656+
return PyErr_NoMemory();
657+
}
655658
size = Py_SIZE(a) + Py_SIZE(b);
656659
np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
657660
if (np == NULL) {
@@ -674,6 +677,9 @@ array_repeat(arrayobject *a, Py_ssize_t n)
674677
Py_ssize_t nbytes;
675678
if (n < 0)
676679
n = 0;
680+
if ((Py_SIZE(a) != 0) && (n > PY_SSIZE_T_MAX / Py_SIZE(a))) {
681+
return PyErr_NoMemory();
682+
}
677683
size = Py_SIZE(a) * n;
678684
np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
679685
if (np == NULL)
@@ -818,6 +824,11 @@ array_do_extend(arrayobject *self, PyObject *bb)
818824
"can only extend with array of same kind");
819825
return -1;
820826
}
827+
if ((Py_SIZE(self) > PY_SSIZE_T_MAX - Py_SIZE(b)) ||
828+
((Py_SIZE(self) + Py_SIZE(b)) > PY_SSIZE_T_MAX / self->ob_descr->itemsize)) {
829+
PyErr_NoMemory();
830+
return -1;
831+
}
821832
size = Py_SIZE(self) + Py_SIZE(b);
822833
PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
823834
if (self->ob_item == NULL) {
@@ -859,6 +870,10 @@ array_inplace_repeat(arrayobject *self, Py_ssize_t n)
859870
if (n < 0)
860871
n = 0;
861872
items = self->ob_item;
873+
if ((self->ob_descr->itemsize != 0) &&
874+
(Py_SIZE(self) > PY_SSIZE_T_MAX / self->ob_descr->itemsize)) {
875+
return PyErr_NoMemory();
876+
}
862877
size = Py_SIZE(self) * self->ob_descr->itemsize;
863878
if (n == 0) {
864879
PyMem_FREE(items);
@@ -867,6 +882,9 @@ array_inplace_repeat(arrayobject *self, Py_ssize_t n)
867882
self->allocated = 0;
868883
}
869884
else {
885+
if (size > PY_SSIZE_T_MAX / n) {
886+
return PyErr_NoMemory();
887+
}
870888
PyMem_Resize(items, char, n * size);
871889
if (items == NULL)
872890
return PyErr_NoMemory();
@@ -1148,6 +1166,10 @@ array_reduce(arrayobject *array)
11481166
Py_INCREF(dict);
11491167
}
11501168
if (Py_SIZE(array) > 0) {
1169+
if (array->ob_descr->itemsize
1170+
> PY_SSIZE_T_MAX / array->ob_size) {
1171+
return PyErr_NoMemory();
1172+
}
11511173
result = Py_BuildValue("O(cs#)O",
11521174
Py_TYPE(array),
11531175
array->ob_descr->typecode,
@@ -1330,6 +1352,9 @@ array_fromlist(arrayobject *self, PyObject *list)
13301352
if ((*self->ob_descr->setitem)(self,
13311353
Py_SIZE(self) - n + i, v) != 0) {
13321354
Py_SIZE(self) -= n;
1355+
if (itemsize && (self->ob_size > PY_SSIZE_T_MAX / itemsize)) {
1356+
return PyErr_NoMemory();
1357+
}
13331358
PyMem_RESIZE(item, char,
13341359
Py_SIZE(self) * itemsize);
13351360
self->ob_item = item;
@@ -1389,6 +1414,10 @@ array_fromstring(arrayobject *self, PyObject *args)
13891414
n = n / itemsize;
13901415
if (n > 0) {
13911416
char *item = self->ob_item;
1417+
if ((n > PY_SSIZE_T_MAX - Py_SIZE(self)) ||
1418+
((Py_SIZE(self) + n) > PY_SSIZE_T_MAX / itemsize)) {
1419+
return PyErr_NoMemory();
1420+
}
13921421
PyMem_RESIZE(item, char, (Py_SIZE(self) + n) * itemsize);
13931422
if (item == NULL) {
13941423
PyErr_NoMemory();
@@ -1414,8 +1443,12 @@ values,as if it had been read from a file using the fromfile() method).");
14141443
static PyObject *
14151444
array_tostring(arrayobject *self, PyObject *unused)
14161445
{
1417-
return PyString_FromStringAndSize(self->ob_item,
1446+
if (self->ob_size <= PY_SSIZE_T_MAX / self->ob_descr->itemsize) {
1447+
return PyString_FromStringAndSize(self->ob_item,
14181448
Py_SIZE(self) * self->ob_descr->itemsize);
1449+
} else {
1450+
return PyErr_NoMemory();
1451+
}
14191452
}
14201453

14211454
PyDoc_STRVAR(tostring_doc,
@@ -1443,6 +1476,9 @@ array_fromunicode(arrayobject *self, PyObject *args)
14431476
}
14441477
if (n > 0) {
14451478
Py_UNICODE *item = (Py_UNICODE *) self->ob_item;
1479+
if (Py_SIZE(self) > PY_SSIZE_T_MAX - n) {
1480+
return PyErr_NoMemory();
1481+
}
14461482
PyMem_RESIZE(item, Py_UNICODE, Py_SIZE(self) + n);
14471483
if (item == NULL) {
14481484
PyErr_NoMemory();

0 commit comments

Comments
 (0)