]> granicus.if.org Git - python/commitdiff
Issue #1621: Avoid signed overflow in list and tuple operations
authorMartin Panter <vadmium+py@gmail.com>
Mon, 25 Jul 2016 02:39:20 +0000 (02:39 +0000)
committerMartin Panter <vadmium+py@gmail.com>
Mon, 25 Jul 2016 02:39:20 +0000 (02:39 +0000)
Patch by Xiang Zhang.

Lib/test/list_tests.py
Misc/NEWS
Objects/listobject.c
Objects/tupleobject.c

index f20fdc0a5f0aa76e15f47148e928acd1a2990836..26e93687f41162dce6bd8b40df3b9410274636f4 100644 (file)
@@ -266,9 +266,21 @@ class CommonTest(seq_tests.CommonTest):
         self.assertEqual(a, list("spameggs"))
 
         self.assertRaises(TypeError, a.extend, None)
-
         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])
         a.insert(0, -2)
index 80c6573ee49fa4be5815a6c6bf81624974ddab82..67ee5497d84dd022b8f25f7e52ae8cf333827d40 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -16,6 +16,9 @@ Core and Builtins
 - 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
index ddc0fee41ab1b2bd45a4b31abe697fcaa99336c3..0b2c8c1dc27a5f9991065e92f294c7ae53237603 100644 (file)
@@ -488,9 +488,9 @@ list_concat(PyListObject *a, PyObject *bb)
         return NULL;
     }
 #define b ((PyListObject *)bb)
-    size = Py_SIZE(a) + Py_SIZE(b);
-    if (size < 0)
+    if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b))
         return PyErr_NoMemory();
+    size = Py_SIZE(a) + Py_SIZE(b);
     np = (PyListObject *) PyList_New(size);
     if (np == NULL) {
         return NULL;
@@ -841,18 +841,20 @@ listextend(PyListObject *self, PyObject *b)
         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 (;;) {
index 1b412580dce111080bf5ad8541d05d743c254280..c0ff499e72c7ddaacb23c818aaa628feefe056a7 100644 (file)
@@ -453,9 +453,9 @@ tupleconcat(PyTupleObject *a, PyObject *bb)
         return NULL;
     }
 #define b ((PyTupleObject *)bb)
-    size = Py_SIZE(a) + Py_SIZE(b);
-    if (size < 0)
+    if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b))
         return PyErr_NoMemory();
+    size = Py_SIZE(a) + Py_SIZE(b);
     np = (PyTupleObject *) PyTuple_New(size);
     if (np == NULL) {
         return NULL;