Issue #24359: Check for changed OrderedDict size during iteration.

This commit is contained in:
Eric Snow 2015-06-01 23:35:13 -06:00
parent d171975609
commit b952ab43f2
3 changed files with 12 additions and 4 deletions

View File

@ -1746,10 +1746,6 @@ class OrderedDictTests:
self.assertEqual(list(reversed(od.items())), list(reversed(pairs))) self.assertEqual(list(reversed(od.items())), list(reversed(pairs)))
def test_detect_deletion_during_iteration(self): 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 OrderedDict = self.module.OrderedDict
od = OrderedDict.fromkeys('abc') od = OrderedDict.fromkeys('abc')
it = iter(od) it = iter(od)

View File

@ -19,6 +19,8 @@ Library
- Issue #24348: Drop superfluous incref/decref. - 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? What's New in Python 3.5.0 beta 2?
================================== ==================================

View File

@ -1796,6 +1796,7 @@ typedef struct {
PyObject_HEAD PyObject_HEAD
int kind; int kind;
PyODictObject *di_odict; PyODictObject *di_odict;
Py_ssize_t di_size;
PyObject *di_current; PyObject *di_current;
PyObject *di_result; /* reusable result tuple for iteritems */ PyObject *di_result; /* reusable result tuple for iteritems */
} odictiterobject; } odictiterobject;
@ -1835,6 +1836,14 @@ odictiter_nextkey(odictiterobject *di)
if (di->di_current == NULL) if (di->di_current == NULL)
goto done; /* We're already done. */ 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. */ /* Get the key. */
node = _odict_find_node(di->di_odict, di->di_current); node = _odict_find_node(di->di_odict, di->di_current);
if (node == NULL) { if (node == NULL) {
@ -2033,6 +2042,7 @@ odictiter_new(PyODictObject *od, int kind)
node = reversed ? _odict_LAST(od) : _odict_FIRST(od); node = reversed ? _odict_LAST(od) : _odict_FIRST(od);
di->di_current = node ? _odictnode_KEY(node) : NULL; di->di_current = node ? _odictnode_KEY(node) : NULL;
Py_XINCREF(di->di_current); Py_XINCREF(di->di_current);
di->di_size = PyODict_SIZE(od);
di->di_odict = od; di->di_odict = od;
Py_INCREF(od); Py_INCREF(od);