mirror of https://github.com/python/cpython
Issue #24369: Defend against key-changes during iteration.
This commit is contained in:
parent
b6c6a4dc04
commit
4fabf02633
|
@ -2047,6 +2047,23 @@ class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
|
||||||
del od[colliding]
|
del od[colliding]
|
||||||
self.assertEqual(list(od.items()), [(key, ...), ('after', ...)])
|
self.assertEqual(list(od.items()), [(key, ...), ('after', ...)])
|
||||||
|
|
||||||
|
def test_key_change_during_iteration(self):
|
||||||
|
OrderedDict = self.module.OrderedDict
|
||||||
|
|
||||||
|
od = OrderedDict.fromkeys('abcde')
|
||||||
|
self.assertEqual(list(od), list('abcde'))
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
for i, k in enumerate(od):
|
||||||
|
od.move_to_end(k)
|
||||||
|
self.assertLess(i, 5)
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
for k in od:
|
||||||
|
od['f'] = None
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
for k in od:
|
||||||
|
del od['c']
|
||||||
|
self.assertEqual(list(od), list('bdeaf'))
|
||||||
|
|
||||||
def test_issue24347(self):
|
def test_issue24347(self):
|
||||||
OrderedDict = self.module.OrderedDict
|
OrderedDict = self.module.OrderedDict
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ Library
|
||||||
|
|
||||||
- Issue #24377: Fix a ref leak in OrderedDict.__repr__.
|
- Issue #24377: Fix a ref leak in OrderedDict.__repr__.
|
||||||
|
|
||||||
|
- Issue #24369: Defend against key-changes during iteration.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 3.5.0 beta 2?
|
What's New in Python 3.5.0 beta 2?
|
||||||
==================================
|
==================================
|
||||||
|
|
|
@ -480,20 +480,15 @@ typedef struct _odictnode _ODictNode;
|
||||||
|
|
||||||
/* PyODictObject */
|
/* PyODictObject */
|
||||||
struct _odictobject {
|
struct _odictobject {
|
||||||
/* od_dict is the underlying dict. */
|
PyDictObject od_dict; /* the underlying dict */
|
||||||
PyDictObject od_dict;
|
_ODictNode *od_first; /* first node in the linked list, if any */
|
||||||
/* od_first is the first node in the odict, if any. */
|
_ODictNode *od_last; /* last node in the linked list, if any */
|
||||||
_ODictNode *od_first;
|
/* od_size and od_fast_nodes are managed by _odict_resize() */
|
||||||
/* od_last is the last node in the odict, if any. */
|
Py_ssize_t od_size; /* hash table that mirrors the dict table */
|
||||||
_ODictNode *od_last;
|
|
||||||
/* od_size is the number of entries in od_fast_nodes. */
|
|
||||||
Py_ssize_t od_size; /* managed by _odict_resize() */
|
|
||||||
/* od_fast_nodes is a hash table that mirrors the dict table. */
|
|
||||||
_ODictNode **od_fast_nodes; /* managed by _odict_resize() */
|
_ODictNode **od_fast_nodes; /* managed by _odict_resize() */
|
||||||
/* od_inst_dict is OrderedDict().__dict__. */
|
size_t od_state; /* incremented whenever the LL changes */
|
||||||
PyObject *od_inst_dict;
|
PyObject *od_inst_dict; /* OrderedDict().__dict__ */
|
||||||
/* od_weakreflist holds weakrefs to the odict. */
|
PyObject *od_weakreflist; /* holds weakrefs to the odict */
|
||||||
PyObject *od_weakreflist;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -608,6 +603,7 @@ _odict_get_index(PyODictObject *od, PyObject *key)
|
||||||
static int
|
static int
|
||||||
_odict_initialize(PyODictObject *od)
|
_odict_initialize(PyODictObject *od)
|
||||||
{
|
{
|
||||||
|
od->od_state = 0;
|
||||||
_odict_FIRST(od) = NULL;
|
_odict_FIRST(od) = NULL;
|
||||||
_odict_LAST(od) = NULL;
|
_odict_LAST(od) = NULL;
|
||||||
return _odict_resize((PyODictObject *)od);
|
return _odict_resize((PyODictObject *)od);
|
||||||
|
@ -642,6 +638,7 @@ _odict_add_head(PyODictObject *od, _ODictNode *node)
|
||||||
_odict_FIRST(od) = node;
|
_odict_FIRST(od) = node;
|
||||||
_odictnode_PREV(_odict_FIRST(od)) = node;
|
_odictnode_PREV(_odict_FIRST(od)) = node;
|
||||||
}
|
}
|
||||||
|
od->od_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -659,6 +656,7 @@ _odict_add_tail(PyODictObject *od, _ODictNode *node)
|
||||||
_odictnode_NEXT(_odict_LAST(od)) = node;
|
_odictnode_NEXT(_odict_LAST(od)) = node;
|
||||||
_odict_LAST(od) = node;
|
_odict_LAST(od) = node;
|
||||||
}
|
}
|
||||||
|
od->od_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adds the node to the end of the list */
|
/* adds the node to the end of the list */
|
||||||
|
@ -725,6 +723,7 @@ _odict_remove_node(PyODictObject *od, _ODictNode *node)
|
||||||
|
|
||||||
_odictnode_PREV(node) = NULL;
|
_odictnode_PREV(node) = NULL;
|
||||||
_odictnode_NEXT(node) = NULL;
|
_odictnode_NEXT(node) = NULL;
|
||||||
|
od->od_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _ODictNode *
|
static _ODictNode *
|
||||||
|
@ -1829,6 +1828,7 @@ typedef struct {
|
||||||
int kind;
|
int kind;
|
||||||
PyODictObject *di_odict;
|
PyODictObject *di_odict;
|
||||||
Py_ssize_t di_size;
|
Py_ssize_t di_size;
|
||||||
|
size_t di_state;
|
||||||
PyObject *di_current;
|
PyObject *di_current;
|
||||||
PyObject *di_result; /* reusable result tuple for iteritems */
|
PyObject *di_result; /* reusable result tuple for iteritems */
|
||||||
} odictiterobject;
|
} odictiterobject;
|
||||||
|
@ -1869,6 +1869,11 @@ odictiter_nextkey(odictiterobject *di)
|
||||||
goto done; /* We're already done. */
|
goto done; /* We're already done. */
|
||||||
|
|
||||||
/* Check for unsupported changes. */
|
/* Check for unsupported changes. */
|
||||||
|
if (di->di_odict->od_state != di->di_state) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"OrderedDict mutated during iteration");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if (di->di_size != PyODict_SIZE(di->di_odict)) {
|
if (di->di_size != PyODict_SIZE(di->di_odict)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
"OrderedDict changed size during iteration");
|
"OrderedDict changed size during iteration");
|
||||||
|
@ -2075,6 +2080,7 @@ odictiter_new(PyODictObject *od, int kind)
|
||||||
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_size = PyODict_SIZE(od);
|
||||||
|
di->di_state = od->od_state;
|
||||||
di->di_odict = od;
|
di->di_odict = od;
|
||||||
Py_INCREF(od);
|
Py_INCREF(od);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue