]> granicus.if.org Git - python/commitdiff
Issue #24359: Check for changed OrderedDict size during iteration.
authorEric Snow <ericsnowcurrently@gmail.com>
Tue, 2 Jun 2015 05:35:13 +0000 (23:35 -0600)
committerEric Snow <ericsnowcurrently@gmail.com>
Tue, 2 Jun 2015 05:35:13 +0000 (23:35 -0600)
Lib/test/test_collections.py
Misc/NEWS
Objects/odictobject.c

index 097aa9afeae8d57e50ce4e94dcaac14e305e3c64..7a1ff14b1723ac75bde2772d26593721eed4ab53 100644 (file)
@@ -1746,10 +1746,6 @@ class OrderedDictTests:
         self.assertEqual(list(reversed(od.items())), list(reversed(pairs)))
 
     def test_detect_deletion_during_iteration(self):
-        # XXX This test should also work under cOrderedDict.
-        if self.module is c_coll:
-            raise unittest.SkipTest("only valid for pure Python OrderedDict")
-
         OrderedDict = self.module.OrderedDict
         od = OrderedDict.fromkeys('abc')
         it = iter(od)
index 75186c86e7da6e1d86ee4a84975a95f925c475f1..c0990ce531dfc8debc89504232730cb2b237401e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -19,6 +19,8 @@ Library
 
 - Issue #24348: Drop superfluous incref/decref.
 
+- Issue #24359: Check for changed OrderedDict size during iteration.
+
 
 What's New in Python 3.5.0 beta 2?
 ==================================
index b91bd680bad096b8c43d87cae685dad2c308d9ba..b44a61ef75a6cb17ef878b3ef65015ed56f6603c 100644 (file)
@@ -1796,6 +1796,7 @@ typedef struct {
     PyObject_HEAD
     int kind;
     PyODictObject *di_odict;
+    Py_ssize_t di_size;
     PyObject *di_current;
     PyObject *di_result; /* reusable result tuple for iteritems */
 } odictiterobject;
@@ -1835,6 +1836,14 @@ odictiter_nextkey(odictiterobject *di)
     if (di->di_current == NULL)
         goto done;  /* We're already done. */
 
+    /* Check for unsupported changes. */
+    if (di->di_size != PyODict_SIZE(di->di_odict)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "OrderedDict changed size during iteration");
+        di->di_size = -1; /* Make this state sticky */
+        return NULL;
+    }
+
     /* Get the key. */
     node = _odict_find_node(di->di_odict, di->di_current);
     if (node == NULL) {
@@ -2033,6 +2042,7 @@ odictiter_new(PyODictObject *od, int kind)
     node = reversed ? _odict_LAST(od) : _odict_FIRST(od);
     di->di_current = node ? _odictnode_KEY(node) : NULL;
     Py_XINCREF(di->di_current);
+    di->di_size = PyODict_SIZE(od);
     di->di_odict = od;
     Py_INCREF(od);