Commits

Martin von Löwis committed 88c1e17

Backport of r61180:
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.

Comments (0)

Files changed (16)

  */
 
 #define PyMem_New(type, n) \
-	( (type *) PyMem_Malloc((n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+	( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
 #define PyMem_NEW(type, n) \
-	( (type *) PyMem_MALLOC((n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+	( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
 
 #define PyMem_Resize(p, type, n) \
-	( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+	( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) )
 #define PyMem_RESIZE(p, type, n) \
-	( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+	( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) )
 
 /* In order to avoid breaking old code mixing PyObject_{New, NEW} with
    PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory"
 #error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)."
 #endif
 
+/* Largest possible value of size_t.
+   SIZE_MAX is part of C99, so it might be defined on some
+   platforms. If it is not defined, (size_t)-1 is a portable
+   definition for C89, due to the way signed->unsigned 
+   conversion is defined. */
+#ifdef SIZE_MAX
+#define PY_SIZE_MAX SIZE_MAX
+#else
+#define PY_SIZE_MAX ((size_t)-1)
+#endif
+
 #ifdef __cplusplus
 }
 #endif
 
 (editors: check NEWS.help for information about editing NEWS using ReST.)
 
+What's New in Python 2.3.7c1?
+===========================
+
+*Release date: 02-Mar-2008*
+
+Core and builtins
+-----------------
+
+- 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.
+
+
 What's New in Python 2.3.6?
 ===========================
 
 		self->field = PyMem_Malloc(self->field_size);
 	}
 	else {
+		if (self->field_size > INT_MAX / 2) {
+			PyErr_NoMemory();
+			return 0;
+		} 
 		self->field_size *= 2;
 		self->field = PyMem_Realloc(self->field, self->field_size);
 	}
 static int
 join_check_rec_size(WriterObj *self, int rec_len)
 {
+
+	if (rec_len < 0 || rec_len > INT_MAX - MEM_INCR) {
+		PyErr_NoMemory();
+		return 0;
+	}
+
 	if (rec_len > self->rec_size) {
 		if (self->rec_size == 0) {
 			self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;

Modules/arraymodule.c

 		PyErr_BadArgument();
 		return NULL;
 	}
+	if (a->ob_size > INT_MAX - b->ob_size) {
+		return PyErr_NoMemory();
+	}
 	size = a->ob_size + b->ob_size;
 	np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
 	if (np == NULL) {
 	int nbytes;
 	if (n < 0)
 		n = 0;
+	if ((a->ob_size != 0) && (n > INT_MAX / a->ob_size)) {
+		return PyErr_NoMemory();
+	}
 	size = a->ob_size * n;
 	np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
 	if (np == NULL)
 			     "can only extend with array of same kind");
 		return -1;
 	}
+	if ((self->ob_size > INT_MAX - b->ob_size) ||
+		((self->ob_size + b->ob_size) > INT_MAX / self->ob_descr->itemsize)) {
+			PyErr_NoMemory();
+			return -1;
+	}
 	size = self->ob_size + b->ob_size;
         PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
         if (self->ob_item == NULL) {
 		if (n < 0)
 			n = 0;
 		items = self->ob_item;
+		if ((self->ob_descr->itemsize != 0) && 
+			(self->ob_size > INT_MAX / self->ob_descr->itemsize)) {
+			return PyErr_NoMemory();
+		}
 		size = self->ob_size * self->ob_descr->itemsize;
 		if (n == 0) {
 			PyMem_FREE(items);
 			self->ob_size = 0;
 		}
 		else {
+			if (size > INT_MAX / n) {
+				return PyErr_NoMemory();
+			}
 			PyMem_Resize(items, char, n * size);
 			if (items == NULL)
 				return PyErr_NoMemory();
 			if ((*self->ob_descr->setitem)(self,
 					self->ob_size - n + i, v) != 0) {
 				self->ob_size -= n;
+				if (itemsize && (self->ob_size > INT_MAX / itemsize)) {
+					return PyErr_NoMemory();
+				}
 				PyMem_RESIZE(item, char,
 					          self->ob_size * itemsize);
 				self->ob_item = item;
 	n = n / itemsize;
 	if (n > 0) {
 		char *item = self->ob_item;
+		if ((n > INT_MAX - self->ob_size) ||
+			((self->ob_size + n) > INT_MAX / itemsize)) {
+				return PyErr_NoMemory();
+		}
 		PyMem_RESIZE(item, char, (self->ob_size + n) * itemsize);
 		if (item == NULL) {
 			PyErr_NoMemory();
 static PyObject *
 array_tostring(arrayobject *self, PyObject *unused)
 {
-	return PyString_FromStringAndSize(self->ob_item,
+	if (self->ob_size <= INT_MAX / self->ob_descr->itemsize) {
+		return PyString_FromStringAndSize(self->ob_item,
 				    self->ob_size * self->ob_descr->itemsize);
+	} else {
+		return PyErr_NoMemory();
+	}
 }
 
 PyDoc_STRVAR(tostring_doc,
 	}
 	if (n > 0) {
 		Py_UNICODE *item = (Py_UNICODE *) self->ob_item;
+		if (self->ob_size > INT_MAX - n) {
+			return PyErr_NoMemory();
+		}
 		PyMem_RESIZE(item, Py_UNICODE, self->ob_size + n);
 		if (item == NULL) {
 			PyErr_NoMemory();

Modules/audioop.c

 audioop_tostereo(PyObject *self, PyObject *args)
 {
 	signed char *cp, *ncp;
-	int len, size, val1, val2, val = 0;
+	int len, new_len, size, val1, val2, val = 0;
 	double fac1, fac2, fval, maxval;
 	PyObject *rv;
 	int i;
 		return 0;
 	}
     
-	rv = PyString_FromStringAndSize(NULL, len*2);
+	new_len = len*2;
+	if (new_len < 0) {
+		PyErr_SetString(PyExc_MemoryError,
+				"not enough memory for output buffer");
+		return 0;
+	}
+
+	rv = PyString_FromStringAndSize(NULL, new_len);
 	if ( rv == 0 )
 		return 0;
 	ncp = (signed char *)PyString_AsString(rv);
 {
 	signed char *cp;
 	unsigned char *ncp;
-	int len, size, size2, val = 0;
+	int len, new_len, size, size2, val = 0;
 	PyObject *rv;
 	int i, j;
 
 		return 0;
 	}
     
-	rv = PyString_FromStringAndSize(NULL, (len/size)*size2);
+	new_len = (len/size)*size2;
+	if (new_len < 0) {
+		PyErr_SetString(PyExc_MemoryError,
+				"not enough memory for output buffer");
+		return 0;
+	}
+	rv = PyString_FromStringAndSize(NULL, new_len);
 	if ( rv == 0 )
 		return 0;
 	ncp = (unsigned char *)PyString_AsString(rv);
 	int chan, d, *prev_i, *cur_i, cur_o;
 	PyObject *state, *samps, *str, *rv = NULL;
 	int bytes_per_frame;
+	size_t alloc_size;
 
 	weightA = 1;
 	weightB = 0;
 	inrate /= d;
 	outrate /= d;
 
-	prev_i = (int *) malloc(nchannels * sizeof(int));
-	cur_i = (int *) malloc(nchannels * sizeof(int));
+	alloc_size = sizeof(int) * (unsigned)nchannels;
+	if (alloc_size < nchannels) {
+		PyErr_SetString(PyExc_MemoryError,
+				"not enough memory for output buffer");
+		return 0;
+	}
+	prev_i = (int *) malloc(alloc_size);
+	cur_i = (int *) malloc(alloc_size);
 	if (prev_i == NULL || cur_i == NULL) {
 		(void) PyErr_NoMemory();
 		goto exit;
 	unsigned char *cp;
 	unsigned char cval;
 	signed char *ncp;
-	int len, size, val;
+	int len, new_len, size, val;
 	PyObject *rv;
 	int i;
 
 		return 0;
 	}
     
-	rv = PyString_FromStringAndSize(NULL, len*size);
+	new_len = len*size;
+	if (new_len < 0) {
+		PyErr_SetString(PyExc_MemoryError,
+			"not enough memory for output buffer");
+		return 0;
+	}
+	rv = PyString_FromStringAndSize(NULL, new_len);
 	if ( rv == 0 )
 		return 0;
 	ncp = (signed char *)PyString_AsString(rv);
     
-	for ( i=0; i < len*size; i += size ) {
+	for ( i=0; i < new_len; i += size ) {
 		cval = *cp++;
 		val = st_ulaw_to_linear(cval);
 	
 {
 	signed char *cp;
 	signed char *ncp;
-	int len, size, valpred, step, delta, index, sign, vpdiff;
+	int len, new_len, size, valpred, step, delta, index, sign, vpdiff;
 	PyObject *rv, *str, *state;
 	int i, inputbuffer = 0, bufferstep;
 
 	} else if ( !PyArg_Parse(state, "(ii)", &valpred, &index) )
 		return 0;
     
-	str = PyString_FromStringAndSize(NULL, len*size*2);
+	new_len = len*size*2;
+	if (new_len < 0) {
+		PyErr_SetString(PyExc_MemoryError,
+				"not enough memory for output buffer");
+		return 0;
+	}
+	str = PyString_FromStringAndSize(NULL, new_len);
 	if ( str == 0 )
 		return 0;
 	ncp = (signed char *)PyString_AsString(str);
 	step = stepsizeTable[index];
 	bufferstep = 0;
     
-	for ( i=0; i < len*size*2; i += size ) {
+	for ( i=0; i < new_len; i += size ) {
 		/* Step 1 - get the delta value and compute next index */
 		if ( bufferstep ) {
 			delta = inputbuffer & 0xf;

Modules/binascii.c

 	if ( !PyArg_ParseTuple(args, "t#:a2b_uu", &ascii_data, &ascii_len) )
 		return NULL;
 
+	assert(ascii_len >= 0);
+
 	/* First byte: binary data length (in bytes) */
 	bin_len = (*ascii_data++ - ' ') & 077;
 	ascii_len--;
 	if ( !PyArg_ParseTuple(args, "t#:a2b_base64", &ascii_data, &ascii_len) )
 		return NULL;
 
+	assert(ascii_len >= 0);
+
+	if (ascii_len > INT_MAX - 3)
+		return PyErr_NoMemory();
+
 	bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */
 
 	/* Allocate the buffer */
 
 	if ( !PyArg_ParseTuple(args, "s#:b2a_base64", &bin_data, &bin_len) )
 		return NULL;
+
+	assert(bin_len >= 0);
+
 	if ( bin_len > BASE64_MAXBIN ) {
 		PyErr_SetString(Error, "Too much data for base64 line");
 		return NULL;
 	if ( !PyArg_ParseTuple(args, "t#:a2b_hqx", &ascii_data, &len) )
 		return NULL;
 
+	assert(len >= 0);
+
+	if (len > INT_MAX - 2)
+		return PyErr_NoMemory();
+
 	/* Allocate a string that is too big (fixed later) */
 	if ( (rv=PyString_FromStringAndSize(NULL, len)) == NULL )
 		return NULL;
 	if ( !PyArg_ParseTuple(args, "s#:rlecode_hqx", &in_data, &len) )
 		return NULL;
 
+	assert(len >= 0);
+
+	if (len > INT_MAX / 2 - 2)
+		return PyErr_NoMemory();
+
 	/* Worst case: output is twice as big as input (fixed later) */
 	if ( (rv=PyString_FromStringAndSize(NULL, len*2)) == NULL )
 		return NULL;
 	if ( !PyArg_ParseTuple(args, "s#:b2a_hqx", &bin_data, &len) )
 		return NULL;
 
+	assert(len >= 0);
+
+	if (len > INT_MAX / 2 - 2)
+		return PyErr_NoMemory();
+
 	/* Allocate a buffer that is at least large enough */
 	if ( (rv=PyString_FromStringAndSize(NULL, len*2)) == NULL )
 		return NULL;
 	if ( !PyArg_ParseTuple(args, "s#:rledecode_hqx", &in_data, &in_len) )
 		return NULL;
 
+	assert(in_len >= 0);
+
 	/* Empty string is a special case */
 	if ( in_len == 0 )
 		return Py_BuildValue("s", "");
+	else if (in_len > INT_MAX / 2)
+		return PyErr_NoMemory();
 
 	/* Allocate a buffer of reasonable size. Resized when needed */
 	out_len = in_len*2;
 #define OUTBYTE(b) \
 	do { \
 		 if ( --out_len_left < 0 ) { \
+			  if ( out_len > INT_MAX / 2) return PyErr_NoMemory(); \
 			  _PyString_Resize(&rv, 2*out_len); \
 			  if ( rv == NULL ) return NULL; \
 			  out_data = (unsigned char *)PyString_AsString(rv) \
 	if ( !PyArg_ParseTuple(args, "s#i:crc_hqx", &bin_data, &len, &crc) )
 		return NULL;
 
-	while(len--) {
+	while(len-- > 0) {
 		crc=((crc<<8)&0xff00)^crctab_hqx[((crc>>8)&0xff)^*bin_data++];
 	}
 
 	/* only want the trailing 32 bits */
 	crc &= 0xFFFFFFFFUL;
 #endif
-	while (len--)
+	while (len-- > 0)
 		crc = crc_32_tab[(crc ^ *bin_data++) & 0xffUL] ^ (crc >> 8);
 		/* Note:  (crc >> 8) MUST zero fill on left */
 
 	if (!PyArg_ParseTuple(args, "t#:b2a_hex", &argbuf, &arglen))
 		return NULL;
 
+	assert(arglen >= 0);
+	if (arglen > INT_MAX / 2)
+		return PyErr_NoMemory();
+
 	retval = PyString_FromStringAndSize(NULL, arglen*2);
 	if (!retval)
 		return NULL;
 	if (!PyArg_ParseTuple(args, "s#:a2b_hex", &argbuf, &arglen))
 		return NULL;
 
+	assert(arglen >= 0);
+
 	/* XXX What should we do about strings with an odd length?  Should
 	 * we add an implicit leading zero, or a trailing zero?  For now,
 	 * raise an exception.

Modules/cPickle.c

 	if (self->read_func(self, &s, 4) < 0) return -1;
 
 	l = calc_binint(s, 4);
+	if (l < 0) {
+		/* Corrupt or hostile pickle -- we never write one like
+		 * this.
+		 */
+		PyErr_SetString(UnpicklingError,
+				"BINSTRING pickle has negative byte count");
+		return -1;
+	}
 
 	if (self->read_func(self, &s, l) < 0)
 		return -1;
 	if (self->read_func(self, &s, 4) < 0) return -1;
 
 	l = calc_binint(s, 4);
+	if (l < 0) {
+		/* Corrupt or hostile pickle -- we never write one like
+		 * this.
+		 */
+		PyErr_SetString(UnpicklingError,
+				"BINUNICODE pickle has negative byte count");
+		return -1;
+	}
 
 	if (self->read_func(self, &s, l) < 0)
 		return -1;

Modules/cStringIO.c

 static PyObject *
 IO_cgetval(PyObject *self) {
         UNLESS (IO__opencheck(IOOOBJECT(self))) return NULL;
+	assert(IOOOBJECT(self)->pos >= 0);
         return PyString_FromStringAndSize(((IOobject*)self)->buf,
                                           ((IOobject*)self)->pos);
 }
         }
         else
                   s=self->string_size;
+        assert(self->pos >= 0);
         return PyString_FromStringAndSize(self->buf, s);
 }
 
         int l;
 
         UNLESS (IO__opencheck(IOOOBJECT(self))) return -1;
+        assert(IOOOBJECT(self)->pos >= 0);
+        assert(IOOOBJECT(self)->string_size >= 0);
         l = ((IOobject*)self)->string_size - ((IOobject*)self)->pos;  
         if (n < 0 || n > l) {
                 n = l;
 
         *output=((IOobject*)self)->buf + ((IOobject*)self)->pos;
         l = n - ((IOobject*)self)->buf - ((IOobject*)self)->pos;
+
+        assert(IOOOBJECT(self)->pos <= INT_MAX - l);
+        assert(IOOOBJECT(self)->pos >= 0);
+        assert(IOOOBJECT(self)->string_size >= 0);
+
         ((IOobject*)self)->pos += l;
         return l;
 }
                 n -= m;
                 self->pos -= m;
         }
+        assert(IOOOBJECT(self)->pos >= 0);
         return PyString_FromStringAndSize(output, n);
 }
 
 
         UNLESS (IO__opencheck(self)) return NULL;
 
+        assert(self->pos >= 0);
         return PyInt_FromLong(self->pos);
 }
 

Modules/datetimemodule.c

 	char sign;
 	int none;
 
+	assert(buflen >= 1);
+
 	offset = call_utcoffset(tzinfo, tzinfoarg, &none);
 	if (offset == -1 && PyErr_Occurred())
 		return -1;
 	 * a new format.  Since computing the replacements for those codes
 	 * is expensive, don't unless they're actually used.
 	 */
+	if (PyString_Size(format) > INT_MAX - 1) {
+		PyErr_NoMemory();
+		goto Done;
+	}
+
 	totalnew = PyString_Size(format) + 1;	/* realistic if no %z/%Z */
 	newfmt = PyString_FromStringAndSize(NULL, totalnew);
 	if (newfmt == NULL) goto Done;

Modules/rgbimgmodule.c

 	Py_Int32 *starttab = NULL, *lengthtab = NULL;
 	FILE *inf = NULL;
 	IMAGE image;
-	int y, z, tablen;
+	int y, z, tablen, new_size;
 	int xsize, ysize, zsize;
 	int bpp, rle, cur, badorder;
 	int rlebuflen;
 	zsize = image.zsize;
 	if (rle) {
 		tablen = ysize * zsize * sizeof(Py_Int32);
+		rlebuflen = (int) (1.05 * xsize +10);
+		if ((tablen / sizeof(Py_Int32)) != (ysize * zsize) ||
+		    rlebuflen < 0) {
+			PyErr_NoMemory();
+			goto finally;
+		}
+
 		starttab = (Py_Int32 *)malloc(tablen);
 		lengthtab = (Py_Int32 *)malloc(tablen);
-		rlebuflen = (int) (1.05 * xsize +10);
 		rledat = (unsigned char *)malloc(rlebuflen);
 		if (!starttab || !lengthtab || !rledat) {
 			PyErr_NoMemory();
 
 		fseek(inf, 512 + 2 * tablen, SEEK_SET);
 		cur = 512 + 2 * tablen;
+		new_size = xsize * ysize + TAGLEN;
+		if (new_size < 0 || (new_size * sizeof(Py_Int32)) < 0) {
+			PyErr_NoMemory();
+			goto finally;
+		}
+
 		rv = PyString_FromStringAndSize((char *)NULL,
-				      (xsize * ysize + TAGLEN) * sizeof(Py_Int32));
+				      new_size * sizeof(Py_Int32));
 		if (rv == NULL)
 			goto finally;
 
 			copybw((Py_Int32 *) base, xsize * ysize);
 	}
 	else {
+		new_size = xsize * ysize + TAGLEN;
+		if (new_size < 0 || (new_size * sizeof(Py_Int32)) < 0) {
+			PyErr_NoMemory();
+			goto finally;
+		}
+
 		rv = PyString_FromStringAndSize((char *) 0,
-					   (xsize*ysize+TAGLEN)*sizeof(Py_Int32));
+						new_size*sizeof(Py_Int32));
 		if (rv == NULL)
 			goto finally;
 
 		return NULL;
 	}
 	tablen = ysize * zsize * sizeof(Py_Int32);
+	rlebuflen = (int) (1.05 * xsize + 10);
+
+	if ((tablen / sizeof(Py_Int32)) != (ysize * zsize) ||
+	    rlebuflen < 0 || (xsize * sizeof(Py_Int32)) < 0) {
+		PyErr_NoMemory();
+		goto finally;
+	}
 
 	starttab = (Py_Int32 *)malloc(tablen);
 	lengthtab = (Py_Int32 *)malloc(tablen);
-	rlebuflen = (int) (1.05 * xsize + 10);
 	rlebuf = (unsigned char *)malloc(rlebuflen);
 	lumbuf = (unsigned char *)malloc(xsize * sizeof(Py_Int32));
 	if (!starttab || !lengthtab || !rlebuf || !lumbuf) {

Modules/stropmodule.c

 	char* e;
 	char* p;
 	char* q;
-	int i, j;
+	int i, j, old_j;
 	PyObject* out;
 	char* string;
 	int stringlen;
 	}
 
 	/* First pass: determine size of output string */
-	i = j = 0; /* j: current column; i: total of previous lines */
+	i = j = old_j = 0; /* j: current column; i: total of previous lines */
 	e = string + stringlen;
 	for (p = string; p < e; p++) {
-		if (*p == '\t')
+		if (*p == '\t') {
 			j += tabsize - (j%tabsize);
-		else {
+			if (old_j > j) {
+				PyErr_SetString(PyExc_OverflowError,
+						"new string is too long");
+				return NULL;
+			}
+			old_j = j;
+		} else {
 			j++;
 			if (*p == '\n') {
 				i += j;
 		}
 	}
 
+	if ((i + j) < 0) {
+		PyErr_SetString(PyExc_OverflowError, "new string is too long");
+		return NULL;
+	}
+
 	/* Second pass: create output string and fill it */
 	out = PyString_FromStringAndSize(NULL, i+j);
 	if (out == NULL)

Objects/bufferobject.c

 				"size must be zero or positive");
 		return NULL;
 	}
+	if (sizeof(*b) > INT_MAX - size) {
+		/* unlikely */
+		return PyErr_NoMemory();
+	}
 	/* Inline PyObject_New */
 	o = PyObject_MALLOC(sizeof(*b) + size);
 	if ( o == NULL )
 	if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
 		return NULL;
 
+	assert(count <= PY_SIZE_MAX - self->b_size);
+
 	ob = PyString_FromStringAndSize(NULL, self->b_size + count);
 	p1 = PyString_AS_STRING(ob);
 	memcpy(p1, self->b_ptr, self->b_size);

Objects/listobject.c

 		return NULL;
 	}
 	nbytes = size * sizeof(PyObject *);
-	/* Check for overflow */
-	if (nbytes / sizeof(PyObject *) != (size_t)size) {
+	/* Check for overflow without an actual overflow,
+	 *  which can cause compiler to optimise out */
+	if (size > PY_SIZE_MAX / sizeof(PyObject *)) {
 		return PyErr_NoMemory();
 	}
 	op = PyObject_GC_New(PyListObject, &PyList_Type);
 	 * we don't care what's in the block.
 	 */
 	merge_freemem(ms);
+	if (need > INT_MAX / sizeof(PyObject*)) {
+		PyErr_NoMemory();
+		return -1;
+	}
 	ms->a = (PyObject **)PyMem_Malloc(need * sizeof(PyObject*));
 	if (ms->a) {
 		ms->alloced = need;
 				return 0;
 			}
 
+			assert(slicelength <= PY_SIZE_MAX / sizeof(PyObject*));
+
 			garbage = (PyObject**)
 				PyMem_MALLOC(slicelength*sizeof(PyObject*));
 
 	if (current_capacity < 0 || required_capacity < 0)
 		return E_OVERFLOW;
 	if (current_capacity < required_capacity) {
+		if (required_capacity > PY_SIZE_MAX / sizeof(node)) {
+			return E_NOMEM;
+		}
 		n = n1->n_child;
 		n = (node *) PyObject_REALLOC(n,
 					      required_capacity * sizeof(node));

Python/bltinmodule.c

 					PyString_AS_STRING(item)[0];
 			} else {
 				/* do we need more space? */
-				int need = j + reslen + len-i-1;
+				int need = j;
+
+				/* calculate space requirements while checking for overflow */
+				if (need > INT_MAX - reslen) {
+					Py_DECREF(item);
+					goto Fail_1;
+				}
+
+				need += reslen;
+
+				if (need > INT_MAX - len) {
+					Py_DECREF(item);
+					goto Fail_1;
+				}
+
+				need += len;
+
+				if (need <= i) {
+					Py_DECREF(item);
+					goto Fail_1;
+				}
+
+				need = need - i - 1;
+
+				assert(need >= 0);
+				assert(outlen >= 0);
+
 				if (need > outlen) {
 					/* overallocate, to avoid reallocations */
-					if (need<2*outlen)
+					if (outlen > INT_MAX / 2) {
+						Py_DECREF(item);
+						return NULL;
+					}
+
+					if (need<2*outlen) {
 						need = 2*outlen;
+          }
 					if (_PyString_Resize(&result, need)) {
 						Py_DECREF(item);
 						return NULL;
 			} else {
 				/* do we need more space? */
 				int need = j + reslen + len-i-1;
+        
+				/* check that didnt overflow */
+				if ((j > INT_MAX - reslen) ||
+					((j + reslen) > INT_MAX - len) ||
+						((j + reslen + len) < i) ||
+							((j + reslen + len - i) <= 0)) {
+					Py_DECREF(item);
+					return NULL;
+				}
+
+				assert(need >= 0);
+				assert(outlen >= 0);
+				
 				if (need > outlen) {
 					/* overallocate, to avoid reallocations */
-					if (need<2*outlen)
-						need = 2*outlen;
+					if (need < 2 * outlen) {
+						if (outlen > INT_MAX / 2) {
+							Py_DECREF(item);
+							return NULL;
+						} else {
+							need = 2 * outlen;
+						}
+					}
+
 					if (PyUnicode_Resize(&result, need)) {
 						Py_DECREF(item);
 						goto Fail_1;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.