Forward-port of r52136,52138: a review of overflow-detecting code.

* unified the way intobject, longobject and mystrtoul handle
  values around -sys.maxint-1.

* in general, trying to entierely avoid overflows in any computation
  involving signed ints or longs is extremely involved.  Fixed a few
  simple cases where a compiler might be too clever (but that's all
  guesswork).

* more overflow checks against bad data in marshal.c.

* 2.5 specific: fixed a number of places that were still confusing int
  and Py_ssize_t.  Some of them could potentially have caused
  "real-world" breakage.

* list.pop(x): fixing overflow issues on x was messy.  I just reverted
  to PyArg_ParseTuple("n"), which does the right thing.  (An obscure
  test was trying to give a Decimal to list.pop()... doesn't make
  sense any more IMHO)

* trying to write a few tests...
This commit is contained in:
Armin Rigo 2006-10-04 12:17:45 +00:00
parent 0d2f498a4c
commit 7ccbca93a2
19 changed files with 186 additions and 106 deletions

View File

@ -269,7 +269,6 @@ class CommonTest(seq_tests.CommonTest):
self.assertRaises(TypeError, a.insert) self.assertRaises(TypeError, a.insert)
def test_pop(self): def test_pop(self):
from decimal import Decimal
a = self.type2test([-1, 0, 1]) a = self.type2test([-1, 0, 1])
a.pop() a.pop()
self.assertEqual(a, [-1, 0]) self.assertEqual(a, [-1, 0])
@ -281,8 +280,6 @@ class CommonTest(seq_tests.CommonTest):
self.assertRaises(IndexError, a.pop) self.assertRaises(IndexError, a.pop)
self.assertRaises(TypeError, a.pop, 42, 42) self.assertRaises(TypeError, a.pop, 42, 42)
a = self.type2test([0, 10, 20, 30, 40]) a = self.type2test([0, 10, 20, 30, 40])
self.assertEqual(a.pop(Decimal(2)), 20)
self.assertRaises(IndexError, a.pop, Decimal(25))
def test_remove(self): def test_remove(self):
a = self.type2test([0, 0, 1]) a = self.type2test([0, 0, 1])

View File

@ -156,6 +156,11 @@ class BuiltinTest(unittest.TestCase):
S = [10, 20, 30] S = [10, 20, 30]
self.assertEqual(any(x > 42 for x in S), False) self.assertEqual(any(x > 42 for x in S), False)
def test_neg(self):
x = -sys.maxint-1
self.assert_(isinstance(x, int))
self.assertEqual(-x, sys.maxint+1)
def test_apply(self): def test_apply(self):
def f0(*args): def f0(*args):
self.assertEqual(args, ()) self.assertEqual(args, ())
@ -702,9 +707,11 @@ class BuiltinTest(unittest.TestCase):
pass pass
s = repr(-1-sys.maxint) s = repr(-1-sys.maxint)
self.assertEqual(int(s)+1, -sys.maxint) x = int(s)
self.assertEqual(x+1, -sys.maxint)
self.assert_(isinstance(x, int))
# should return long # should return long
int(s[1:]) self.assertEqual(int(s[1:]), sys.maxint+1)
# should return long # should return long
x = int(1e100) x = int(1e100)

View File

@ -247,17 +247,23 @@ class LongTest(unittest.TestCase):
"long(-sys.maxint-1) != -sys.maxint-1") "long(-sys.maxint-1) != -sys.maxint-1")
# long -> int should not fail for hugepos_aslong or hugeneg_aslong # long -> int should not fail for hugepos_aslong or hugeneg_aslong
x = int(hugepos_aslong)
try: try:
self.assertEqual(int(hugepos_aslong), hugepos, self.assertEqual(x, hugepos,
"converting sys.maxint to long and back to int fails") "converting sys.maxint to long and back to int fails")
except OverflowError: except OverflowError:
self.fail("int(long(sys.maxint)) overflowed!") self.fail("int(long(sys.maxint)) overflowed!")
if not isinstance(x, int):
raise TestFailed("int(long(sys.maxint)) should have returned int")
x = int(hugeneg_aslong)
try: try:
self.assertEqual(int(hugeneg_aslong), hugeneg, self.assertEqual(x, hugeneg,
"converting -sys.maxint-1 to long and back to int fails") "converting -sys.maxint-1 to long and back to int fails")
except OverflowError: except OverflowError:
self.fail("int(long(-sys.maxint-1)) overflowed!") self.fail("int(long(-sys.maxint-1)) overflowed!")
if not isinstance(x, int):
raise TestFailed("int(long(-sys.maxint-1)) should have "
"returned int")
# but long -> int should overflow for hugepos+1 and hugeneg-1 # but long -> int should overflow for hugepos+1 and hugeneg-1
x = hugepos_aslong + 1 x = hugepos_aslong + 1
try: try:
@ -282,6 +288,17 @@ class LongTest(unittest.TestCase):
self.assert_(type(y) is long, self.assert_(type(y) is long,
"overflowing int conversion must return long not long subtype") "overflowing int conversion must return long not long subtype")
# long -> Py_ssize_t conversion
class X(object):
def __getslice__(self, i, j):
return i, j
self.assertEqual(X()[-5L:7L], (-5, 7))
# use the clamping effect to test the smallest and largest longs
# that fit a Py_ssize_t
slicemin, slicemax = X()[-2L**100:2L**100]
self.assertEqual(X()[slicemin:slicemax], (slicemin, slicemax))
# ----------------------------------- tests of auto int->long conversion # ----------------------------------- tests of auto int->long conversion
def test_auto_overflow(self): def test_auto_overflow(self):

View File

@ -12,8 +12,14 @@ What's New in Python 2.6 alpha 1?
Core and builtins Core and builtins
----------------- -----------------
- Integer negation and absolute value were fixed to not rely - list.pop(x) accepts any object x following the __index__ protocol.
on undefined behaviour of the C compiler anymore.
- Fix some leftovers from the conversion from int to Py_ssize_t
(relevant to strings and sequences of more than 2**31 items).
- A number of places, including integer negation and absolute value,
were fixed to not rely on undefined behaviour of the C compiler
anymore.
- Bug #1566800: make sure that EnvironmentError can be called with any - Bug #1566800: make sure that EnvironmentError can be called with any
number of arguments, as was the case in Python 2.4. number of arguments, as was the case in Python 2.4.

View File

@ -1024,7 +1024,7 @@ save_int(Picklerobject *self, PyObject *args)
static int static int
save_long(Picklerobject *self, PyObject *args) save_long(Picklerobject *self, PyObject *args)
{ {
int size; Py_ssize_t size;
int res = -1; int res = -1;
PyObject *repr = NULL; PyObject *repr = NULL;
@ -1066,7 +1066,7 @@ save_long(Picklerobject *self, PyObject *args)
* byte at the start, and cut it back later if possible. * byte at the start, and cut it back later if possible.
*/ */
nbytes = (nbits >> 3) + 1; nbytes = (nbits >> 3) + 1;
if ((int)nbytes < 0 || (size_t)(int)nbytes != nbytes) { if (nbytes > INT_MAX) {
PyErr_SetString(PyExc_OverflowError, "long too large " PyErr_SetString(PyExc_OverflowError, "long too large "
"to pickle"); "to pickle");
goto finally; goto finally;
@ -1208,12 +1208,14 @@ save_string(Picklerobject *self, PyObject *args, int doput)
c_str[1] = size; c_str[1] = size;
len = 2; len = 2;
} }
else { else if (size <= INT_MAX) {
c_str[0] = BINSTRING; c_str[0] = BINSTRING;
for (i = 1; i < 5; i++) for (i = 1; i < 5; i++)
c_str[i] = (int)(size >> ((i - 1) * 8)); c_str[i] = (int)(size >> ((i - 1) * 8));
len = 5; len = 5;
} }
else
return -1; /* string too large */
if (self->write_func(self, c_str, len) < 0) if (self->write_func(self, c_str, len) < 0)
return -1; return -1;
@ -1286,7 +1288,7 @@ modified_EncodeRawUnicodeEscape(const Py_UNICODE *s, int size)
static int static int
save_unicode(Picklerobject *self, PyObject *args, int doput) save_unicode(Picklerobject *self, PyObject *args, int doput)
{ {
int size, len; Py_ssize_t size, len;
PyObject *repr=0; PyObject *repr=0;
if (!PyUnicode_Check(args)) if (!PyUnicode_Check(args))
@ -1325,6 +1327,8 @@ save_unicode(Picklerobject *self, PyObject *args, int doput)
if ((size = PyString_Size(repr)) < 0) if ((size = PyString_Size(repr)) < 0)
goto err; goto err;
if (size > INT_MAX)
return -1; /* string too large */
c_str[0] = BINUNICODE; c_str[0] = BINUNICODE;
for (i = 1; i < 5; i++) for (i = 1; i < 5; i++)

View File

@ -1652,20 +1652,18 @@ _PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation)
if (cmp > 0) { if (cmp > 0) {
switch (operation) { switch (operation) {
case PY_ITERSEARCH_COUNT: case PY_ITERSEARCH_COUNT:
++n; if (n == PY_SSIZE_T_MAX) {
if (n <= 0) {
/* XXX(nnorwitz): int means ssize_t */
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"count exceeds C int size"); "count exceeds C integer size");
goto Fail; goto Fail;
} }
++n;
break; break;
case PY_ITERSEARCH_INDEX: case PY_ITERSEARCH_INDEX:
if (wrapped) { if (wrapped) {
/* XXX(nnorwitz): int means ssize_t */
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"index exceeds C int size"); "index exceeds C integer size");
goto Fail; goto Fail;
} }
goto Done; goto Done;
@ -1680,9 +1678,9 @@ _PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation)
} }
if (operation == PY_ITERSEARCH_INDEX) { if (operation == PY_ITERSEARCH_INDEX) {
++n; if (n == PY_SSIZE_T_MAX)
if (n <= 0)
wrapped = 1; wrapped = 1;
++n;
} }
} }

View File

@ -1001,6 +1001,7 @@ getline_via_fgets(FILE *fp)
size_t nfree; /* # of free buffer slots; pvend-pvfree */ size_t nfree; /* # of free buffer slots; pvend-pvfree */
size_t total_v_size; /* total # of slots in buffer */ size_t total_v_size; /* total # of slots in buffer */
size_t increment; /* amount to increment the buffer */ size_t increment; /* amount to increment the buffer */
size_t prev_v_size;
/* Optimize for normal case: avoid _PyString_Resize if at all /* Optimize for normal case: avoid _PyString_Resize if at all
* possible via first reading into stack buffer "buf". * possible via first reading into stack buffer "buf".
@ -1115,8 +1116,11 @@ getline_via_fgets(FILE *fp)
/* expand buffer and try again */ /* expand buffer and try again */
assert(*(pvend-1) == '\0'); assert(*(pvend-1) == '\0');
increment = total_v_size >> 2; /* mild exponential growth */ increment = total_v_size >> 2; /* mild exponential growth */
prev_v_size = total_v_size;
total_v_size += increment; total_v_size += increment;
if (total_v_size > PY_SSIZE_T_MAX) { /* check for overflow */
if (total_v_size <= prev_v_size ||
total_v_size > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"line is longer than a Python string can hold"); "line is longer than a Python string can hold");
Py_DECREF(v); Py_DECREF(v);
@ -1125,7 +1129,7 @@ getline_via_fgets(FILE *fp)
if (_PyString_Resize(&v, (int)total_v_size) < 0) if (_PyString_Resize(&v, (int)total_v_size) < 0)
return NULL; return NULL;
/* overwrite the trailing null byte */ /* overwrite the trailing null byte */
pvfree = BUF(v) + (total_v_size - increment - 1); pvfree = BUF(v) + (prev_v_size - 1);
} }
if (BUF(v) + total_v_size != p) if (BUF(v) + total_v_size != p)
_PyString_Resize(&v, p - BUF(v)); _PyString_Resize(&v, p - BUF(v));

View File

@ -546,6 +546,17 @@ int_mul(PyObject *v, PyObject *w)
} }
} }
/* Integer overflow checking for unary negation: on a 2's-complement
* box, -x overflows iff x is the most negative long. In this case we
* get -x == x. However, -x is undefined (by C) if x /is/ the most
* negative long (it's a signed overflow case), and some compilers care.
* So we cast x to unsigned long first. However, then other compilers
* warn about applying unary minus to an unsigned operand. Hence the
* weird "0-".
*/
#define UNARY_NEG_WOULD_OVERFLOW(x) \
((x) < 0 && (unsigned long)(x) == 0-(unsigned long)(x))
/* Return type of i_divmod */ /* Return type of i_divmod */
enum divmod_result { enum divmod_result {
DIVMOD_OK, /* Correct result */ DIVMOD_OK, /* Correct result */
@ -565,7 +576,7 @@ i_divmod(register long x, register long y,
return DIVMOD_ERROR; return DIVMOD_ERROR;
} }
/* (-sys.maxint-1)/-1 is the only overflow case. */ /* (-sys.maxint-1)/-1 is the only overflow case. */
if (y == -1 && x == LONG_MIN) if (y == -1 && UNARY_NEG_WOULD_OVERFLOW(x))
return DIVMOD_OVERFLOW; return DIVMOD_OVERFLOW;
xdivy = x / y; xdivy = x / y;
xmody = x - xdivy * y; xmody = x - xdivy * y;
@ -756,7 +767,8 @@ int_neg(PyIntObject *v)
{ {
register long a; register long a;
a = v->ob_ival; a = v->ob_ival;
if (a < 0 && (unsigned long)a == 0-(unsigned long)a) { /* check for overflow */
if (UNARY_NEG_WOULD_OVERFLOW(a)) {
PyObject *o = PyLong_FromLong(a); PyObject *o = PyLong_FromLong(a);
if (o != NULL) { if (o != NULL) {
PyObject *result = PyNumber_Negative(o); PyObject *result = PyNumber_Negative(o);

View File

@ -863,17 +863,12 @@ static PyObject *
listpop(PyListObject *self, PyObject *args) listpop(PyListObject *self, PyObject *args)
{ {
Py_ssize_t i = -1; Py_ssize_t i = -1;
PyObject *v, *arg = NULL; PyObject *v;
int status; int status;
if (!PyArg_UnpackTuple(args, "pop", 0, 1, &arg)) if (!PyArg_ParseTuple(args, "|n:pop", &i))
return NULL; return NULL;
if (arg != NULL) {
if (PyInt_Check(arg))
i = PyInt_AS_LONG((PyIntObject*) arg);
else if (!PyArg_ParseTuple(args, "|n:pop", &i))
return NULL;
}
if (self->ob_size == 0) { if (self->ob_size == 0) {
/* Special-case most common failure cause */ /* Special-case most common failure cause */
PyErr_SetString(PyExc_IndexError, "pop from empty list"); PyErr_SetString(PyExc_IndexError, "pop from empty list");

View File

@ -193,6 +193,18 @@ PyLong_FromDouble(double dval)
return (PyObject *)v; return (PyObject *)v;
} }
/* Checking for overflow in PyLong_AsLong is a PITA since C doesn't define
* anything about what happens when a signed integer operation overflows,
* and some compilers think they're doing you a favor by being "clever"
* then. The bit pattern for the largest postive signed long is
* (unsigned long)LONG_MAX, and for the smallest negative signed long
* it is abs(LONG_MIN), which we could write -(unsigned long)LONG_MIN.
* However, some other compilers warn about applying unary minus to an
* unsigned operand. Hence the weird "0-".
*/
#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
#define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN)
/* Get a C long int from a long int object. /* Get a C long int from a long int object.
Returns -1 and sets an error condition if overflow occurs. */ Returns -1 and sets an error condition if overflow occurs. */
@ -225,14 +237,16 @@ PyLong_AsLong(PyObject *vv)
if ((x >> SHIFT) != prev) if ((x >> SHIFT) != prev)
goto overflow; goto overflow;
} }
/* Haven't lost any bits, but if the sign bit is set we're in /* Haven't lost any bits, but casting to long requires extra care
* trouble *unless* this is the min negative number. So, * (see comment above).
* trouble iff sign bit set && (positive || some bit set other
* than the sign bit).
*/ */
if ((long)x < 0 && (sign > 0 || (x << 1) != 0)) if (x <= (unsigned long)LONG_MAX) {
goto overflow;
return (long)x * sign; return (long)x * sign;
}
else if (sign < 0 && x == PY_ABS_LONG_MIN) {
return LONG_MIN;
}
/* else overflow */
overflow: overflow:
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
@ -268,14 +282,16 @@ _PyLong_AsSsize_t(PyObject *vv) {
if ((x >> SHIFT) != prev) if ((x >> SHIFT) != prev)
goto overflow; goto overflow;
} }
/* Haven't lost any bits, but if the sign bit is set we're in /* Haven't lost any bits, but casting to a signed type requires
* trouble *unless* this is the min negative number. So, * extra care (see comment above).
* trouble iff sign bit set && (positive || some bit set other
* than the sign bit).
*/ */
if ((Py_ssize_t)x < 0 && (sign > 0 || (x << 1) != 0)) if (x <= (size_t)PY_SSIZE_T_MAX) {
goto overflow;
return (Py_ssize_t)x * sign; return (Py_ssize_t)x * sign;
}
else if (sign < 0 && x == PY_ABS_SSIZE_T_MIN) {
return PY_SSIZE_T_MIN;
}
/* else overflow */
overflow: overflow:
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
@ -1167,7 +1183,7 @@ long_format(PyObject *aa, int base, int addL)
{ {
register PyLongObject *a = (PyLongObject *)aa; register PyLongObject *a = (PyLongObject *)aa;
PyStringObject *str; PyStringObject *str;
Py_ssize_t i; Py_ssize_t i, j, sz;
Py_ssize_t size_a; Py_ssize_t size_a;
char *p; char *p;
int bits; int bits;
@ -1187,11 +1203,18 @@ long_format(PyObject *aa, int base, int addL)
++bits; ++bits;
i >>= 1; i >>= 1;
} }
i = 5 + (addL ? 1 : 0) + (size_a*SHIFT + bits-1) / bits; i = 5 + (addL ? 1 : 0);
str = (PyStringObject *) PyString_FromStringAndSize((char *)0, i); j = size_a*SHIFT + bits-1;
sz = i + j / bits;
if (j / SHIFT < size_a || sz < i) {
PyErr_SetString(PyExc_OverflowError,
"long is too large to format");
return NULL;
}
str = (PyStringObject *) PyString_FromStringAndSize((char *)0, sz);
if (str == NULL) if (str == NULL)
return NULL; return NULL;
p = PyString_AS_STRING(str) + i; p = PyString_AS_STRING(str) + sz;
*p = '\0'; *p = '\0';
if (addL) if (addL)
*--p = 'L'; *--p = 'L';
@ -1305,7 +1328,7 @@ long_format(PyObject *aa, int base, int addL)
} while ((*q++ = *p++) != '\0'); } while ((*q++ = *p++) != '\0');
q--; q--;
_PyString_Resize((PyObject **)&str, _PyString_Resize((PyObject **)&str,
(int) (q - PyString_AS_STRING(str))); (Py_ssize_t) (q - PyString_AS_STRING(str)));
} }
return (PyObject *)str; return (PyObject *)str;
} }
@ -1363,14 +1386,14 @@ long_from_binary_base(char **str, int base)
while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base) while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base)
++p; ++p;
*str = p; *str = p;
n = (p - start) * bits_per_char; /* n <- # of Python digits needed, = ceiling(n/SHIFT). */
if (n / bits_per_char != p - start) { n = (p - start) * bits_per_char + SHIFT - 1;
if (n / bits_per_char < p - start) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"long string too large to convert"); "long string too large to convert");
return NULL; return NULL;
} }
/* n <- # of Python digits needed, = ceiling(n/SHIFT). */ n = n / SHIFT;
n = (n + SHIFT - 1) / SHIFT;
z = _PyLong_New(n); z = _PyLong_New(n);
if (z == NULL) if (z == NULL)
return NULL; return NULL;

View File

@ -804,10 +804,22 @@ string_print(PyStringObject *op, FILE *fp, int flags)
return ret; return ret;
} }
if (flags & Py_PRINT_RAW) { if (flags & Py_PRINT_RAW) {
char *data = op->ob_sval;
Py_ssize_t size = op->ob_size;
while (size > INT_MAX) {
/* Very long strings cannot be written atomically.
* But don't write exactly INT_MAX bytes at a time
* to avoid memory aligment issues.
*/
const int chunk_size = INT_MAX & ~0x3FFF;
fwrite(data, 1, chunk_size, fp);
data += chunk_size;
size -= chunk_size;
}
#ifdef __VMS #ifdef __VMS
if (op->ob_size) fwrite(op->ob_sval, (int) op->ob_size, 1, fp); if (size) fwrite(data, (int)size, 1, fp);
#else #else
fwrite(op->ob_sval, 1, (int) op->ob_size, fp); fwrite(data, 1, (int)size, fp);
#endif #endif
return 0; return 0;
} }
@ -844,7 +856,7 @@ PyString_Repr(PyObject *obj, int smartquotes)
register PyStringObject* op = (PyStringObject*) obj; register PyStringObject* op = (PyStringObject*) obj;
size_t newsize = 2 + 4 * op->ob_size; size_t newsize = 2 + 4 * op->ob_size;
PyObject *v; PyObject *v;
if (newsize > PY_SSIZE_T_MAX) { if (newsize > PY_SSIZE_T_MAX || newsize / 4 != op->ob_size) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"string is too large to make repr"); "string is too large to make repr");
} }
@ -4237,7 +4249,7 @@ _PyString_FormatLong(PyObject *val, int flags, int prec, int type,
return NULL; return NULL;
} }
llen = PyString_Size(result); llen = PyString_Size(result);
if (llen > PY_SSIZE_T_MAX) { if (llen > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "string too large in _PyString_FormatLong"); PyErr_SetString(PyExc_ValueError, "string too large in _PyString_FormatLong");
return NULL; return NULL;
} }
@ -4726,9 +4738,10 @@ PyString_Format(PyObject *format, PyObject *args)
default: default:
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"unsupported format character '%c' (0x%x) " "unsupported format character '%c' (0x%x) "
"at index %i", "at index %zd",
c, c, c, c,
(int)(fmt - 1 - PyString_AsString(format))); (Py_ssize_t)(fmt - 1 -
PyString_AsString(format)));
goto error; goto error;
} }
if (sign) { if (sign) {

View File

@ -98,7 +98,7 @@ type_module(PyTypeObject *type, void *context)
s = strrchr(type->tp_name, '.'); s = strrchr(type->tp_name, '.');
if (s != NULL) if (s != NULL)
return PyString_FromStringAndSize( return PyString_FromStringAndSize(
type->tp_name, (int)(s - type->tp_name)); type->tp_name, (Py_ssize_t)(s - type->tp_name));
return PyString_FromString("__builtin__"); return PyString_FromString("__builtin__");
} }
} }
@ -4116,17 +4116,8 @@ slot_sq_length(PyObject *self)
return -1; return -1;
len = PyInt_AsSsize_t(res); len = PyInt_AsSsize_t(res);
Py_DECREF(res); Py_DECREF(res);
if (len == -1 && PyErr_Occurred())
return -1;
#if SIZEOF_SIZE_T < SIZEOF_INT
/* Overflow check -- range of PyInt is more than C ssize_t */
if (len != (int)len) {
PyErr_SetString(PyExc_OverflowError,
"__len__() should return 0 <= outcome < 2**31");
return -1;
}
#endif
if (len < 0) { if (len < 0) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"__len__() should return >= 0"); "__len__() should return >= 0");
return -1; return -1;

View File

@ -2384,6 +2384,7 @@ PyObject *_PyUnicode_DecodeUnicodeInternal(const char *s,
Py_UNICODE unimax = PyUnicode_GetMax(); Py_UNICODE unimax = PyUnicode_GetMax();
#endif #endif
/* XXX overflow detection missing */
v = _PyUnicode_New((size+Py_UNICODE_SIZE-1)/ Py_UNICODE_SIZE); v = _PyUnicode_New((size+Py_UNICODE_SIZE-1)/ Py_UNICODE_SIZE);
if (v == NULL) if (v == NULL)
goto onError; goto onError;
@ -3170,6 +3171,7 @@ PyObject *PyUnicode_DecodeCharmap(const char *s,
Py_ssize_t needed = (targetsize - extrachars) + \ Py_ssize_t needed = (targetsize - extrachars) + \
(targetsize << 2); (targetsize << 2);
extrachars += needed; extrachars += needed;
/* XXX overflow detection missing */
if (_PyUnicode_Resize(&v, if (_PyUnicode_Resize(&v,
PyUnicode_GET_SIZE(v) + needed) < 0) { PyUnicode_GET_SIZE(v) + needed) < 0) {
Py_DECREF(x); Py_DECREF(x);
@ -7762,10 +7764,11 @@ PyObject *PyUnicode_Format(PyObject *format,
default: default:
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"unsupported format character '%c' (0x%x) " "unsupported format character '%c' (0x%x) "
"at index %i", "at index %zd",
(31<=c && c<=126) ? (char)c : '?', (31<=c && c<=126) ? (char)c : '?',
(int)c, (int)c,
(int)(fmt -1 - PyUnicode_AS_UNICODE(uformat))); (Py_ssize_t)(fmt - 1 -
PyUnicode_AS_UNICODE(uformat)));
goto onError; goto onError;
} }
if (sign) { if (sign) {

View File

@ -551,7 +551,8 @@ PyErr_NewException(char *name, PyObject *base, PyObject *dict)
goto failure; goto failure;
} }
if (PyDict_GetItemString(dict, "__module__") == NULL) { if (PyDict_GetItemString(dict, "__module__") == NULL) {
modulename = PyString_FromStringAndSize(name, (int)(dot-name)); modulename = PyString_FromStringAndSize(name,
(Py_ssize_t)(dot-name));
if (modulename == NULL) if (modulename == NULL)
goto failure; goto failure;
if (PyDict_SetItemString(dict, "__module__", modulename) != 0) if (PyDict_SetItemString(dict, "__module__", modulename) != 0)

View File

@ -815,7 +815,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
#endif #endif
else else
return converterr("string", arg, msgbuf, bufsize); return converterr("string", arg, msgbuf, bufsize);
if ((int)strlen(*p) != PyString_Size(arg)) if ((Py_ssize_t)strlen(*p) != PyString_Size(arg))
return converterr("string without null bytes", return converterr("string without null bytes",
arg, msgbuf, bufsize); arg, msgbuf, bufsize);
} }
@ -882,7 +882,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
format++; format++;
} }
else if (*p != NULL && else if (*p != NULL &&
(int)strlen(*p) != PyString_Size(arg)) (Py_ssize_t)strlen(*p) != PyString_Size(arg))
return converterr( return converterr(
"string without null bytes or None", "string without null bytes or None",
arg, msgbuf, bufsize); arg, msgbuf, bufsize);
@ -1029,7 +1029,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
PyMem_Free()ing it after usage PyMem_Free()ing it after usage
*/ */
if ((int)strlen(PyString_AS_STRING(s)) != size) { if ((Py_ssize_t)strlen(PyString_AS_STRING(s))
!= size) {
Py_DECREF(s); Py_DECREF(s);
return converterr( return converterr(
"(encoded string without NULL bytes)", "(encoded string without NULL bytes)",

View File

@ -546,6 +546,11 @@ r_object(RFILE *p)
int size; int size;
PyLongObject *ob; PyLongObject *ob;
n = r_long(p); n = r_long(p);
if (n < -INT_MAX || n > INT_MAX) {
PyErr_SetString(PyExc_ValueError,
"bad marshal data");
return NULL;
}
size = n<0 ? -n : n; size = n<0 ? -n : n;
ob = _PyLong_New(size); ob = _PyLong_New(size);
if (ob == NULL) if (ob == NULL)
@ -654,7 +659,7 @@ r_object(RFILE *p)
case TYPE_INTERNED: case TYPE_INTERNED:
case TYPE_STRING: case TYPE_STRING:
n = r_long(p); n = r_long(p);
if (n < 0) { if (n < 0 || n > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "bad marshal data"); PyErr_SetString(PyExc_ValueError, "bad marshal data");
return NULL; return NULL;
} }
@ -689,7 +694,7 @@ r_object(RFILE *p)
char *buffer; char *buffer;
n = r_long(p); n = r_long(p);
if (n < 0) { if (n < 0 || n > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "bad marshal data"); PyErr_SetString(PyExc_ValueError, "bad marshal data");
return NULL; return NULL;
} }
@ -710,7 +715,7 @@ r_object(RFILE *p)
case TYPE_TUPLE: case TYPE_TUPLE:
n = r_long(p); n = r_long(p);
if (n < 0) { if (n < 0 || n > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "bad marshal data"); PyErr_SetString(PyExc_ValueError, "bad marshal data");
return NULL; return NULL;
} }
@ -733,7 +738,7 @@ r_object(RFILE *p)
case TYPE_LIST: case TYPE_LIST:
n = r_long(p); n = r_long(p);
if (n < 0) { if (n < 0 || n > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "bad marshal data"); PyErr_SetString(PyExc_ValueError, "bad marshal data");
return NULL; return NULL;
} }
@ -831,10 +836,11 @@ r_object(RFILE *p)
v = NULL; v = NULL;
argcount = r_long(p); /* XXX ignore long->int overflows for now */
nlocals = r_long(p); argcount = (int)r_long(p);
stacksize = r_long(p); nlocals = (int)r_long(p);
flags = r_long(p); stacksize = (int)r_long(p);
flags = (int)r_long(p);
code = r_object(p); code = r_object(p);
if (code == NULL) if (code == NULL)
goto code_error; goto code_error;
@ -859,7 +865,7 @@ r_object(RFILE *p)
name = r_object(p); name = r_object(p);
if (name == NULL) if (name == NULL)
goto code_error; goto code_error;
firstlineno = r_long(p); firstlineno = (int)r_long(p);
lnotab = r_object(p); lnotab = r_object(p);
if (lnotab == NULL) if (lnotab == NULL)
goto code_error; goto code_error;
@ -1031,10 +1037,16 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
wf.strings = (version > 0) ? PyDict_New() : NULL; wf.strings = (version > 0) ? PyDict_New() : NULL;
w_object(x, &wf); w_object(x, &wf);
Py_XDECREF(wf.strings); Py_XDECREF(wf.strings);
if (wf.str != NULL) if (wf.str != NULL) {
_PyString_Resize(&wf.str, char *base = PyString_AS_STRING((PyStringObject *)wf.str);
(int) (wf.ptr - if (wf.ptr - base > PY_SSIZE_T_MAX) {
PyString_AS_STRING((PyStringObject *)wf.str))); Py_DECREF(wf.str);
PyErr_SetString(PyExc_OverflowError,
"too much marshall data for a string");
return NULL;
}
_PyString_Resize(&wf.str, (Py_ssize_t)(wf.ptr - base));
}
if (wf.error) { if (wf.error) {
Py_XDECREF(wf.str); Py_XDECREF(wf.str);
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,

View File

@ -421,7 +421,7 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags)
"string too long for Python string"); "string too long for Python string");
return NULL; return NULL;
} }
n = (int)m; n = (Py_ssize_t)m;
} }
v = PyString_FromStringAndSize(str, n); v = PyString_FromStringAndSize(str, n);
} }

View File

@ -195,13 +195,10 @@ overflowed:
return (unsigned long)-1; return (unsigned long)-1;
} }
/* Checking for overflow in PyOS_strtol is a PITA since C doesn't define /* Checking for overflow in PyOS_strtol is a PITA; see comments
* anything about what happens when a signed integer operation overflows, * about PY_ABS_LONG_MIN in longobject.c.
* and some compilers think they're doing you a favor by being "clever"
* then. Python assumes a 2's-complement representation, so that the bit
* pattern for the largest postive signed long is LONG_MAX, and for
* the smallest negative signed long is LONG_MAX + 1.
*/ */
#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
long long
PyOS_strtol(char *str, char **ptr, int base) PyOS_strtol(char *str, char **ptr, int base)
@ -224,8 +221,7 @@ PyOS_strtol(char *str, char **ptr, int base)
if (sign == '-') if (sign == '-')
result = -result; result = -result;
} }
else if (sign == '-' && uresult == (unsigned long)LONG_MAX + 1) { else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
assert(LONG_MIN == -LONG_MAX-1);
result = LONG_MIN; result = LONG_MIN;
} }
else { else {

View File

@ -1225,7 +1225,7 @@ makepathobject(char *path, int delim)
p = strchr(path, delim); p = strchr(path, delim);
if (p == NULL) if (p == NULL)
p = strchr(path, '\0'); /* End of string */ p = strchr(path, '\0'); /* End of string */
w = PyString_FromStringAndSize(path, (int) (p - path)); w = PyString_FromStringAndSize(path, (Py_ssize_t) (p - path));
if (w == NULL) { if (w == NULL) {
Py_DECREF(v); Py_DECREF(v);
return NULL; return NULL;