Merge from 3.5.

This commit is contained in:
Eric Snow 2015-06-04 00:12:14 -06:00
commit f02dcc8803
3 changed files with 38 additions and 13 deletions

View File

@ -2055,6 +2055,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

View File

@ -39,6 +39,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?
================================== ==================================

View File

@ -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);