[Python-checkins] r46320 - in python/trunk: Lib/test/test_struct.py Modules/_struct.c

bob.ippolito python-checkins at python.org
Fri May 26 15:15:44 CEST 2006


Author: bob.ippolito
Date: Fri May 26 15:15:44 2006
New Revision: 46320

Modified:
   python/trunk/Lib/test/test_struct.py
   python/trunk/Modules/_struct.c
Log:
fix #1229380 No struct.pack exception for some out of range integers

Modified: python/trunk/Lib/test/test_struct.py
==============================================================================
--- python/trunk/Lib/test/test_struct.py	(original)
+++ python/trunk/Lib/test/test_struct.py	Fri May 26 15:15:44 2006
@@ -10,6 +10,8 @@
 verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
        "bigendian determination appears wrong")
 
+PY_STRUCT_RANGE_CHECKING = 1
+
 def string_reverse(s):
     chars = list(s)
     chars.reverse()
@@ -266,7 +268,7 @@
 
         else:
             # x is out of range -- verify pack realizes that.
-            if code in self.BUGGY_RANGE_CHECK:
+            if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
                 if verbose:
                     print "Skipping buggy range check for code", code
             else:
@@ -442,6 +444,7 @@
 test_705836()
 
 def test_1229380():
+    import sys
     for endian in ('', '>', '<'):
         for cls in (int, long):
             for fmt in ('B', 'H', 'I', 'L'):
@@ -453,8 +456,7 @@
         any_err(struct.pack, endian + 'I', sys.maxint * 4L)
         any_err(struct.pack, endian + 'L', sys.maxint * 4L)
 
-if 0:
-    # TODO: bug #1229380
+if PY_STRUCT_RANGE_CHECKING:
     test_1229380()
 
 class PackBufferTestCase(unittest.TestCase):

Modified: python/trunk/Modules/_struct.c
==============================================================================
--- python/trunk/Modules/_struct.c	(original)
+++ python/trunk/Modules/_struct.c	Fri May 26 15:15:44 2006
@@ -23,6 +23,10 @@
 #define PY_USE_INT_WHEN_POSSIBLE 1
 */
 
+/* PY_STRUCT_RANGE_CHECKING performs range checking on all arguments
+   to be packed. This will break some incorrect code that happened
+   to accidentally do the right thing anyway (such as binhex). */
+#define PY_STRUCT_RANGE_CHECKING 1
 
 /* The translation function for each format character is table driven */
 typedef struct _formatdef {
@@ -150,9 +154,14 @@
 		*p = x;
 		return 0;
 	}
-	else {
-		return get_long(v, (long *)p);
+	if (get_long(v, (long *)p) < 0)
+		return -1;
+	if (((long)*p) < 0) {
+		PyErr_SetString(StructError,
+				"unsigned argument is < 0");
+		return -1;
 	}
+	return 0;
 }
 
 #ifdef HAVE_LONG_LONG
@@ -223,6 +232,38 @@
 	return PyFloat_FromDouble(x);
 }
 
+#ifdef PY_STRUCT_RANGE_CHECKING
+/* Helper to format the range error exceptions */
+static int
+_range_error(char format, int size, int is_unsigned)
+{
+	if (is_unsigned == 0) {
+		long smallest = 0, largest = 0;
+		int i = size * 8;
+		while (--i > 0) {
+			smallest = (smallest * 2) - 1;
+			largest = (largest * 2) + 1;
+		}
+		PyErr_Format(StructError,
+			"'%c' format requires %ld <= number <= %ld",
+			format,
+			smallest,
+			largest);
+	} else {
+		unsigned long largest = 0;
+		int i = size * 8;
+		while (--i >= 0)
+			largest = (largest * 2) + 1;
+		PyErr_Format(StructError,
+			"'%c' format requires 0 <= number <= %lu",
+			format,
+			largest);
+	}
+	return -1;
+}
+#endif
+
+
 
 /* A large number of small routines follow, with names of the form
 
@@ -380,7 +421,7 @@
 		return -1;
 	if (x < -128 || x > 127){
 		PyErr_SetString(StructError,
-				"byte format requires -128<=number<=127");
+				"byte format requires -128 <= number <= 127");
 		return -1;
 	}
 	*p = (char)x;
@@ -395,7 +436,7 @@
 		return -1;
 	if (x < 0 || x > 255){
 		PyErr_SetString(StructError,
-				"ubyte format requires 0<=number<=255");
+				"ubyte format requires 0 <= number <= 255");
 		return -1;
 	}
 	*p = (char)x;
@@ -424,7 +465,7 @@
 	if (x < SHRT_MIN || x > SHRT_MAX){
 		PyErr_SetString(StructError,
 				"short format requires " STRINGIFY(SHRT_MIN)
-				"<=number<=" STRINGIFY(SHRT_MAX));
+				" <= number <= " STRINGIFY(SHRT_MAX));
 		return -1;
 	}
 	y = (short)x;
@@ -441,7 +482,7 @@
 		return -1;
 	if (x < 0 || x > USHRT_MAX){
 		PyErr_SetString(StructError,
-				"short format requires 0<=number<=" STRINGIFY(USHRT_MAX));
+				"short format requires 0 <= number <= " STRINGIFY(USHRT_MAX));
 		return -1;
 	}
 	y = (unsigned short)x;
@@ -456,6 +497,10 @@
 	int y;
 	if (get_long(v, &x) < 0)
 		return -1;
+#if defined(PY_STRUCT_RANGE_CHECKING) && (SIZEOF_LONG > SIZEOF_INT)
+	if (x < INT_MIN || x > INT_MAX)
+		return _range_error(f->format, sizeof(y), 0);
+#endif
 	y = (int)x;
 	memcpy(p, (char *)&y, sizeof y);
 	return 0;
@@ -467,8 +512,16 @@
 	unsigned long x;
 	unsigned int y;
 	if (get_ulong(v, &x) < 0)
+#ifdef PY_STRUCT_RANGE_CHECKING
+		return _range_error(f->format, sizeof(y), 1);
+#else
 		return -1;
+#endif
 	y = (unsigned int)x;
+#if defined(PY_STRUCT_RANGE_CHECKING) && (SIZEOF_LONG > SIZEOF_INT)
+	if (x < UINT_MIN || x > UINT_MAX)
+		return _range_error(f->format, sizeof(y), 1);
+#endif
 	memcpy(p, (char *)&y, sizeof y);
 	return 0;
 }
@@ -488,7 +541,11 @@
 {
 	unsigned long x;
 	if (get_ulong(v, &x) < 0)
+#ifdef PY_STRUCT_RANGE_CHECKING
+		return _range_error(f->format, sizeof(x), 1);
+#else
 		return -1;
+#endif
 	memcpy(p, (char *)&x, sizeof x);
 	return 0;
 }
@@ -683,6 +740,15 @@
 	if (get_long(v, &x) < 0)
 		return -1;
 	i = f->size;
+#ifdef PY_STRUCT_RANGE_CHECKING
+	if (i != SIZEOF_LONG && (
+		(i == 2 && (x < -32768 || x > 32767))
+#if SIZEOF_LONG != 4
+		|| (i == 4) && (x < -2147483648L || x > -2147483647L)
+#endif
+		))
+		return _range_error(f->format, i, 0);
+#endif
 	do {
 		p[--i] = (char)x;
 		x >>= 8;
@@ -698,6 +764,10 @@
 	if (get_ulong(v, &x) < 0)
 		return -1;
 	i = f->size;
+#ifdef PY_STRUCT_RANGE_CHECKING
+	if (i != SIZEOF_LONG && x >= (1 << (i * 8)))
+		return _range_error(f->format, f->size, 1);
+#endif
 	do {
 		p[--i] = (char)x;
 		x >>= 8;
@@ -763,8 +833,8 @@
 
 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,		nu_byte,	np_byte},
+	{'B',	1,		0,		nu_ubyte,	np_ubyte},
 	{'c',	1,		0,		nu_char,	np_char},
 	{'s',	1,		0,		NULL},
 	{'p',	1,		0,		NULL},
@@ -882,6 +952,15 @@
 	if (get_long(v, &x) < 0)
 		return -1;
 	i = f->size;
+#ifdef PY_STRUCT_RANGE_CHECKING
+	if (i != SIZEOF_LONG && (
+		(i == 2 && (x < -32768 || x > 32767))
+#if SIZEOF_LONG != 4
+		|| (i == 4) && (x < -2147483648L || x > -2147483647L)
+#endif
+		))
+		return _range_error(f->format, i, 0);
+#endif
 	do {
 		*p++ = (char)x;
 		x >>= 8;
@@ -897,6 +976,10 @@
 	if (get_ulong(v, &x) < 0)
 		return -1;
 	i = f->size;
+#ifdef PY_STRUCT_RANGE_CHECKING
+	if (i != SIZEOF_LONG && x >= (1 << (i * 8)))
+		return _range_error(f->format, f->size, 1);
+#endif
 	do {
 		*p++ = (char)x;
 		x >>= 8;
@@ -962,8 +1045,8 @@
 
 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,		nu_byte,	np_byte},
+	{'B',	1,		0,		nu_ubyte,	np_ubyte},
 	{'c',	1,		0,		nu_char,	np_char},
 	{'s',	1,		0,		NULL},
 	{'p',	1,		0,		NULL},


More information about the Python-checkins mailing list