]> granicus.if.org Git - python/commitdiff
bpo-36452: dictiter: track maximum iteration count (GH-12596)
authorThomas Perl <m@thp.io>
Thu, 28 Mar 2019 06:03:25 +0000 (07:03 +0100)
committerInada Naoki <songofacandy@gmail.com>
Thu, 28 Mar 2019 06:03:25 +0000 (15:03 +0900)
Lib/test/test_dict.py
Misc/NEWS.d/next/Core and Builtins/2019-03-27-23-53-00.bpo-36452.xhK2lT.rst [new file with mode: 0644]
Objects/dictobject.c

index 03afd5b2a6c75e65698b102e2123e5c74797a37c..eecdc8beec694eece46a439e303cfaaa72591b01 100644 (file)
@@ -470,6 +470,15 @@ class DictTest(unittest.TestCase):
             for i in d:
                 d[i+1] = 1
 
+    def test_mutating_iteration_delete(self):
+        # change dict content during iteration
+        d = {}
+        d[0] = 0
+        with self.assertRaises(RuntimeError):
+            for i in d:
+                del d[0]
+                d[1] = 1
+
     def test_mutating_lookup(self):
         # changing dict during a lookup (issue #14417)
         class NastyKey:
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-03-27-23-53-00.bpo-36452.xhK2lT.rst b/Misc/NEWS.d/next/Core and Builtins/2019-03-27-23-53-00.bpo-36452.xhK2lT.rst
new file mode 100644 (file)
index 0000000..37c0c50
--- /dev/null
@@ -0,0 +1 @@
+Changing `dict` keys during iteration will now be detected in certain corner cases where the number of keys isn't changed (but they keys themselves are), and a `RuntimeError` will be raised.
\ No newline at end of file
index e2603e190b62ef951639fe6b7823735ce7649743..7ea979cd17611612a676271fa6e4b3435e4f958d 100644 (file)
@@ -3543,6 +3543,12 @@ dictiter_iternextkey(dictiterobject *di)
             goto fail;
         key = entry_ptr->me_key;
     }
+    // We found an element (key), but did not expect it
+    if (di->len == 0) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "dictionary keys changed during iteration");
+        goto fail;
+    }
     di->di_pos = i+1;
     di->len--;
     Py_INCREF(key);