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

mark.dickinson python-checkins at python.org
Fri Jun 11 22:08:36 CEST 2010


Author: mark.dickinson
Date: Fri Jun 11 22:08:36 2010
New Revision: 81903

Log:
Merged revisions 81897-81898,81902 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/branches/py3k

........
  r81897 | mark.dickinson | 2010-06-11 17:56:34 +0100 (Fri, 11 Jun 2010) | 1 line
  
  Avoid possible undefined behaviour from signed overflow.
........
  r81898 | mark.dickinson | 2010-06-11 20:05:08 +0100 (Fri, 11 Jun 2010) | 1 line
  
  Fix an incorrect return type.
........
  r81902 | mark.dickinson | 2010-06-11 20:50:30 +0100 (Fri, 11 Jun 2010) | 1 line
  
  Fix more undefined-behaviour inducing overflow checks in struct module.
........


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

Modified: python/branches/release31-maint/Lib/test/test_struct.py
==============================================================================
--- python/branches/release31-maint/Lib/test/test_struct.py	(original)
+++ python/branches/release31-maint/Lib/test/test_struct.py	Fri Jun 11 22:08:36 2010
@@ -511,6 +511,13 @@
             for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
                 self.assertTrue(struct.unpack('>?', c)[0])
 
+    def test_count_overflow(self):
+        hugecount = '{}b'.format(sys.maxsize+1)
+        self.assertRaises(struct.error, struct.calcsize, hugecount)
+
+        hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
+        self.assertRaises(struct.error, struct.calcsize, hugecount2)
+
     if IS32BIT:
         def test_crasher(self):
             self.assertRaises(MemoryError, struct.pack, "357913941b", "a")

Modified: python/branches/release31-maint/Modules/_struct.c
==============================================================================
--- python/branches/release31-maint/Modules/_struct.c	(original)
+++ python/branches/release31-maint/Modules/_struct.c	Fri Jun 11 22:08:36 2010
@@ -1132,16 +1132,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;
@@ -1160,7 +1163,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 = PyBytes_AS_STRING(self->s_format);
 
@@ -1175,14 +1178,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;
@@ -1203,13 +1205,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 */
@@ -1268,6 +1270,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