[Python-checkins] cpython: Issue #1621: Avoid signed overflow in list and tuple operations

martin.panter python-checkins at python.org
Sun Jul 24 23:44:25 EDT 2016


https://hg.python.org/cpython/rev/db93af6080e7
changeset:   102448:db93af6080e7
user:        Martin Panter <vadmium+py at gmail.com>
date:        Mon Jul 25 02:39:20 2016 +0000
summary:
  Issue #1621: Avoid signed overflow in list and tuple operations

Patch by Xiang Zhang.

files:
  Lib/test/list_tests.py |  14 +++++++++++++-
  Misc/NEWS              |   3 +++
  Objects/listobject.c   |  18 ++++++++++--------
  Objects/tupleobject.c  |   4 ++--
  4 files changed, 28 insertions(+), 11 deletions(-)


diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py
--- a/Lib/test/list_tests.py
+++ b/Lib/test/list_tests.py
@@ -266,8 +266,20 @@
         self.assertEqual(a, list("spameggs"))
 
         self.assertRaises(TypeError, a.extend, None)
+        self.assertRaises(TypeError, a.extend)
 
-        self.assertRaises(TypeError, a.extend)
+        # overflow test. issue1621
+        class CustomIter:
+            def __iter__(self):
+                return self
+            def __next__(self):
+                raise StopIteration
+            def __length_hint__(self):
+                return sys.maxsize
+        a = self.type2test([1,2,3,4])
+        a.extend(CustomIter())
+        self.assertEqual(a, [1,2,3,4])
+
 
     def test_insert(self):
         a = self.type2test([0, 1, 2])
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -16,6 +16,9 @@
 - Issue #27581: Don't rely on wrapping for overflow check in
   PySequence_Tuple().  Patch by Xiang Zhang.
 
+- Issue #1621: Avoid signed integer overflow in list and tuple operations.
+  Patch by Xiang Zhang.
+
 - Issue #27419: Standard __import__() no longer look up "__import__" in globals
   or builtins for importing submodules or "from import".  Fixed a crash if
   raise a warning about unabling to resolve package from __spec__ or
diff --git a/Objects/listobject.c b/Objects/listobject.c
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -488,9 +488,9 @@
         return NULL;
     }
 #define b ((PyListObject *)bb)
+    if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b))
+        return PyErr_NoMemory();
     size = Py_SIZE(a) + Py_SIZE(b);
-    if (size < 0)
-        return PyErr_NoMemory();
     np = (PyListObject *) PyList_New(size);
     if (np == NULL) {
         return NULL;
@@ -841,18 +841,20 @@
         return NULL;
     }
     m = Py_SIZE(self);
-    mn = m + n;
-    if (mn >= m) {
+    if (m > PY_SSIZE_T_MAX - n) {
+        /* m + n overflowed; on the chance that n lied, and there really
+         * is enough room, ignore it.  If n was telling the truth, we'll
+         * eventually run out of memory during the loop.
+         */
+    }
+    else {
+        mn = m + n;
         /* Make room. */
         if (list_resize(self, mn) < 0)
             goto error;
         /* Make the list sane again. */
         Py_SIZE(self) = m;
     }
-    /* Else m + n overflowed; on the chance that n lied, and there really
-     * is enough room, ignore it.  If n was telling the truth, we'll
-     * eventually run out of memory during the loop.
-     */
 
     /* Run iterator to exhaustion. */
     for (;;) {
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -453,9 +453,9 @@
         return NULL;
     }
 #define b ((PyTupleObject *)bb)
+    if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b))
+        return PyErr_NoMemory();
     size = Py_SIZE(a) + Py_SIZE(b);
-    if (size < 0)
-        return PyErr_NoMemory();
     np = (PyTupleObject *) PyTuple_New(size);
     if (np == NULL) {
         return NULL;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list