[Python-checkins] r81935 - in python/branches/release26-maint: Lib/test/test_struct.py Modules/_struct.c

mark.dickinson python-checkins at python.org
Sat Jun 12 10:49:43 CEST 2010


Author: mark.dickinson
Date: Sat Jun 12 10:49:42 2010
New Revision: 81935

Log:
Merged revisions 81904 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r81904 | mark.dickinson | 2010-06-11 21:27:05 +0100 (Fri, 11 Jun 2010) | 4 lines
  
  Fix possible undefined behaviour from signed overflow in struct module.
  
  Backport of revisions 81897, 81898 and 81902 from py3k.
........


Modified:
   python/branches/release26-maint/   (props changed)
   python/branches/release26-maint/Lib/test/test_struct.py
   python/branches/release26-maint/Modules/_struct.c

Modified: python/branches/release26-maint/Lib/test/test_struct.py
==============================================================================
--- python/branches/release26-maint/Lib/test/test_struct.py	(original)
+++ python/branches/release26-maint/Lib/test/test_struct.py	Sat Jun 12 10:49:42 2010
@@ -12,7 +12,6 @@
 import sys
 ISBIGENDIAN = sys.byteorder == "big"
 IS32BIT = sys.maxsize == 0x7fffffff
-del sys
 
 try:
     import _struct
@@ -605,7 +604,12 @@
         def test_crasher(self):
             self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
 
+    def test_count_overflow(self):
+        hugecount = '{0}b'.format(sys.maxsize+1)
+        self.assertRaises(struct.error, struct.calcsize, hugecount)
 
+        hugecount2 = '{0}b{1}H'.format(sys.maxsize//2, sys.maxsize//2)
+        self.assertRaises(struct.error, struct.calcsize, hugecount2)
 
 def test_main():
     run_unittest(StructTest)

Modified: python/branches/release26-maint/Modules/_struct.c
==============================================================================
--- python/branches/release26-maint/Modules/_struct.c	(original)
+++ python/branches/release26-maint/Modules/_struct.c	Sat Jun 12 10:49:42 2010
@@ -1309,16 +1309,19 @@
 }
 
 
-/* Align a size according to a format code */
+/* Align a size according to a format code.  Return -1 on overflow. */
 
-static int
+static Py_ssize_t
 align(Py_ssize_t size, char c, const formatdef *e)
 {
+    Py_ssize_t extra;
+
     if (e->format == c) {
-        if (e->alignment) {
-            size = ((size + e->alignment - 1)
-                / e->alignment)
-                * e->alignment;
+        if (e->alignment && size > 0) {
+            extra = (e->alignment - 1) - (size - 1) % (e->alignment);
+            if (extra > PY_SSIZE_T_MAX - size)
+                return -1;
+            size += extra;
         }
     }
     return size;
@@ -1337,7 +1340,7 @@
     const char *s;
     const char *fmt;
     char c;
-    Py_ssize_t size, len, num, itemsize, x;
+    Py_ssize_t size, len, num, itemsize;
 
     fmt = PyString_AS_STRING(self->s_format);
 
@@ -1352,14 +1355,13 @@
         if ('0' <= c && c <= '9') {
             num = c - '0';
             while ('0' <= (c = *s++) && c <= '9') {
-                x = num*10 + (c - '0');
-                if (x/10 != num) {
-                    PyErr_SetString(
-                        StructError,
-                        "overflow in item count");
-                    return -1;
-                }
-                num = x;
+                /* overflow-safe version of
+                   if (num*10 + (c - '0') > PY_SSIZE_T_MAX) { ... } */
+                if (num >= PY_SSIZE_T_MAX / 10 && (
+                        num > PY_SSIZE_T_MAX / 10 ||
+                        (c - '0') > PY_SSIZE_T_MAX % 10))
+                    goto overflow;
+                num = num*10 + (c - '0');
             }
             if (c == '\0')
                 break;
@@ -1380,13 +1382,13 @@
 
         itemsize = e->size;
         size = align(size, c, e);
-        x = num * itemsize;
-        size += x;
-        if (x/itemsize != num || size < 0) {
-            PyErr_SetString(StructError,
-                            "total struct size too long");
-            return -1;
-        }
+        if (size == -1)
+            goto overflow;
+
+        /* if (size + num * itemsize > PY_SSIZE_T_MAX) { ... } */
+        if (num > (PY_SSIZE_T_MAX - size) / itemsize)
+            goto overflow;
+        size += num * itemsize;
     }
 
     /* check for overflow */
@@ -1445,6 +1447,11 @@
     codes->size = 0;
 
     return 0;
+
+  overflow:
+    PyErr_SetString(StructError,
+                    "total struct size too long");
+    return -1;
 }
 
 static PyObject *


More information about the Python-checkins mailing list