Index: dist/src/Lib/test/test_struct.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_struct.py,v retrieving revision 1.19 diff -u -r1.19 test_struct.py --- dist/src/Lib/test/test_struct.py 27 Sep 2004 19:27:50 -0000 1.19 +++ dist/src/Lib/test/test_struct.py 8 Oct 2004 05:51:10 -0000 @@ -185,12 +185,6 @@ class IntTester: - # XXX Most std integer modes fail to test for out-of-range. - # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but - # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C - # reported by Mark Favas). - BUGGY_RANGE_CHECK = "bBhHiIlL" - def __init__(self, formatpair, bytesize): assert len(formatpair) == 2 self.formatpair = formatpair @@ -263,12 +257,8 @@ else: # x is out of range -- verify pack realizes that. - if code in self.BUGGY_RANGE_CHECK: - if verbose: - print "Skipping buggy range check for code", code - else: - any_err(pack, ">" + code, x) - any_err(pack, "<" + code, x) + any_err(pack, ">" + code, x) + any_err(pack, "<" + code, x) # Much the same for unsigned. code = self.unsigned_code @@ -318,12 +308,8 @@ else: # x is out of range -- verify pack realizes that. - if code in self.BUGGY_RANGE_CHECK: - if verbose: - print "Skipping buggy range check for code", code - else: - any_err(pack, ">" + code, x) - any_err(pack, "<" + code, x) + any_err(pack, ">" + code, x) + any_err(pack, "<" + code, x) def run(self): from random import randrange Index: dist/src/Modules/structmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/structmodule.c,v retrieving revision 2.62 diff -u -r2.62 structmodule.c --- dist/src/Modules/structmodule.c 27 Sep 2004 19:27:51 -0000 2.62 +++ dist/src/Modules/structmodule.c 8 Oct 2004 05:51:11 -0000 @@ -100,38 +100,62 @@ /* Helper routine to get a Python integer and raise the appropriate error if it isn't one */ + static int get_long(PyObject *v, long *p) { - long x = PyInt_AsLong(v); - if (x == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_SetString(StructError, - "required argument is not an integer"); + if (PyLong_Check(v)) { + long x = PyLong_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); + return -1; + } + *p = x; + } else if (PyInt_Check (v)) { + long x = PyInt_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); + return -1; + } + *p = x; + } else { + PyErr_SetString(StructError, + "cannot convert argument (not an integer)"); return -1; } - *p = x; return 0; } - -/* Same, but handling unsigned long */ - static int get_ulong(PyObject *v, unsigned long *p) { if (PyLong_Check(v)) { unsigned long x = PyLong_AsUnsignedLong(v); - if (x == (unsigned long)(-1) && PyErr_Occurred()) + if (x == (unsigned long)-1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); return -1; + } *p = x; - return 0; - } - else { - return get_long(v, (long *)p); + } else if (PyInt_Check (v)) { + unsigned long x = PyLong_AsUnsignedLong(PyLong_FromLong(PyInt_AS_LONG(v))); + if (x == (unsigned long)-1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); + return -1; + } + *p = x; + } else { + PyErr_SetString(StructError, + "cannot convert argument (not an integer)"); + return -1; } + return 0; } + #ifdef HAVE_LONG_LONG /* Same, but handling native long long. */ @@ -349,7 +373,7 @@ np_byte(char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(v, &x) < 0) + if (get_long(v, &x) < 0) return -1; if (x < -128 || x > 127){ PyErr_SetString(StructError, @@ -364,9 +388,9 @@ np_ubyte(char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(v, &x) < 0) + if (get_long(v, &x) < 0) return -1; - if (x < 0 || x > 255){ + if (x > 255){ PyErr_SetString(StructError, "ubyte format requires 0<=number<=255"); return -1; @@ -392,7 +416,7 @@ { long x; short y; - if (get_long(v, &x) < 0) + if (get_long(v, &x) < 0) return -1; if (x < SHRT_MIN || x > SHRT_MAX){ PyErr_SetString(StructError, @@ -410,9 +434,9 @@ { long x; unsigned short y; - if (get_long(v, &x) < 0) + if (get_ulong(v, &x) < 0) return -1; - if (x < 0 || x > USHRT_MAX){ + if (x > USHRT_MAX){ PyErr_SetString(StructError, "short format requires 0<=number<=" STRINGIFY(USHRT_MAX)); return -1; @@ -427,8 +451,15 @@ { long x; int y; - if (get_long(v, &x) < 0) + if (get_long(v, &x) < 0) + return -1; + if (x < INT_MIN || x > INT_MAX){ + PyErr_SetString(StructError, + "int format requires " STRINGIFY(SHRT_MIN) + "<=number<=" STRINGIFY(SHRT_MAX)); return -1; + } + y = (int)x; memcpy(p, (char *)&y, sizeof y); return 0; @@ -439,8 +470,14 @@ { unsigned long x; unsigned int y; - if (get_ulong(v, &x) < 0) + if (get_long(v, &x) < 0) + return -1; + if (x > UINT_MAX){ + PyErr_SetString(StructError, + "int format requires 0<=number<=" STRINGIFY(UINT_MAX)); return -1; + } + y = (unsigned int)x; memcpy(p, (char *)&y, sizeof y); return 0; @@ -450,7 +487,7 @@ np_long(char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(v, &x) < 0) + if (get_long(v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; @@ -460,7 +497,7 @@ np_ulong(char *p, PyObject *v, const formatdef *f) { unsigned long x; - if (get_ulong(v, &x) < 0) + if (get_ulong(v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; @@ -619,14 +656,28 @@ bp_int(char *p, PyObject *v, const formatdef *f) { long x; - int i; - if (get_long(v, &x) < 0) + if (get_long(v, &x) < 0) return -1; - i = f->size; - do { - p[--i] = (char)x; - x >>= 8; - } while (i > 0); + switch (f->size) { + case 1: + p[0] = (char)x; + break; + case 2: + p[1] = (char)x; + p[0] = (char)(x>>8); + break; + case 4: + p[3] = (char)x; + p[2] = (char)(x>>8); + p[1] = (char)(x>>16); + p[0] = (char)(x>>24); + break; + } + if (((x > 0) && x>>(f->size*8-1)) || ((x < 0) && ~(x>>(f->size*8-1)))) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); + return -1; + } return 0; } @@ -634,14 +685,29 @@ bp_uint(char *p, PyObject *v, const formatdef *f) { unsigned long x; - int i; - if (get_ulong(v, &x) < 0) + if (get_ulong(v, &x) < 0) return -1; - i = f->size; - do { - p[--i] = (char)x; - x >>= 8; - } while (i > 0); + switch (f->size) { + case 1: + p[0] = (char)x; + break; + case 2: + p[1] = (char)x; + p[0] = (char)(x>>8); + break; + case 4: + p[3] = (char)x; + p[2] = (char)(x>>8); + p[1] = (char)(x>>16); + p[0] = (char)(x>>24); + break; + } + /* if f->size==sizeof(long), get_ulong() took care of overflows */ + if (f->size != sizeof(long) && x>>(f->size*8)) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); + return -1; + } return 0; } @@ -704,7 +770,7 @@ static formatdef bigendian_table[] = { {'x', 1, 0, NULL}, {'b', 1, 0, bu_int, bp_int}, - {'B', 1, 0, bu_uint, bp_int}, + {'B', 1, 0, bu_uint, bp_uint}, {'c', 1, 0, nu_char, np_char}, {'s', 1, 0, NULL}, {'p', 1, 0, NULL}, @@ -785,14 +851,28 @@ lp_int(char *p, PyObject *v, const formatdef *f) { long x; - int i; - if (get_long(v, &x) < 0) + if (get_long(v, &x) < 0) return -1; - i = f->size; - do { - *p++ = (char)x; - x >>= 8; - } while (--i > 0); + switch (f->size) { + case 1: + p[0] = (char)x; + break; + case 2: + p[0] = (char)x; + p[1] = (char)(x>>8); + break; + case 4: + p[0] = (char)x; + p[1] = (char)(x>>8); + p[2] = (char)(x>>16); + p[3] = (char)(x>>24); + break; + } + if (((x > 0) && x>>(f->size*8-1)) || ((x < 0) && ~(x>>(f->size*8-1)))) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); + return -1; + } return 0; } @@ -800,14 +880,29 @@ lp_uint(char *p, PyObject *v, const formatdef *f) { unsigned long x; - int i; - if (get_ulong(v, &x) < 0) + if (get_ulong(v, &x) < 0) return -1; - i = f->size; - do { - *p++ = (char)x; - x >>= 8; - } while (--i > 0); + switch (f->size) { + case 1: + p[0] = (char)x; + break; + case 2: + p[0] = (char)x; + p[1] = (char)(x>>8); + break; + case 4: + p[0] = (char)x; + p[1] = (char)(x>>8); + p[2] = (char)(x>>16); + p[3] = (char)(x>>24); + break; + } + /* if f->size==sizeof(long), get_ulong() took care of overflows*/ + if (f->size != sizeof(long) && x>>(f->size*8)) { + PyErr_SetString(StructError, + "cannot convert argument (overflow)"); + return -1; + } return 0; } @@ -870,7 +965,7 @@ static formatdef lilendian_table[] = { {'x', 1, 0, NULL}, {'b', 1, 0, lu_int, lp_int}, - {'B', 1, 0, lu_uint, lp_int}, + {'B', 1, 0, lu_uint, lp_uint}, {'c', 1, 0, nu_char, np_char}, {'s', 1, 0, NULL}, {'p', 1, 0, NULL},