[Python-checkins] r81902 - in python/branches/py3k: Lib/test/test_struct.py Modules/_struct.c

mark.dickinson python-checkins at python.org
Fri Jun 11 21:50:30 CEST 2010


Author: mark.dickinson
Date: Fri Jun 11 21:50:30 2010
New Revision: 81902

Log:
Fix more undefined-behaviour inducing overflow checks in struct module.

Modified:
   python/branches/py3k/Lib/test/test_struct.py
   python/branches/py3k/Modules/_struct.c

Modified: python/branches/py3k/Lib/test/test_struct.py
==============================================================================
--- python/branches/py3k/Lib/test/test_struct.py	(original)
+++ python/branches/py3k/Lib/test/test_struct.py	Fri Jun 11 21:50:30 2010
@@ -510,6 +510,8 @@
         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):

Modified: python/branches/py3k/Modules/_struct.c
==============================================================================
--- python/branches/py3k/Modules/_struct.c	(original)
+++ python/branches/py3k/Modules/_struct.c	Fri Jun 11 21:50:30 2010
@@ -1143,16 +1143,19 @@
 }
 
 
-/* Align a size according to a format code */
+/* Align a size according to a format code.  Return -1 on overflow. */
 
 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;
@@ -1171,7 +1174,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);
 
@@ -1190,12 +1193,8 @@
                    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)) {
-                    PyErr_SetString(
-                        StructError,
-                        "overflow in item count");
-                    return -1;
-                }
+                        (c - '0') > PY_SSIZE_T_MAX % 10))
+                    goto overflow;
                 num = num*10 + (c - '0');
             }
             if (c == '\0') {
@@ -1220,13 +1219,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 */
@@ -1285,6 +1284,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