@@ -480,20 +480,15 @@ typedef struct _odictnode _ODictNode;
480480
481481/* PyODictObject */
482482struct _odictobject {
483- /* od_dict is the underlying dict. */
484- PyDictObject od_dict ;
485- /* od_first is the first node in the odict, if any. */
486- _ODictNode * od_first ;
487- /* od_last is the last node in the odict, if any. */
488- _ODictNode * od_last ;
489- /* od_size is the number of entries in od_fast_nodes. */
490- Py_ssize_t od_size ; /* managed by _odict_resize() */
491- /* od_fast_nodes is a hash table that mirrors the dict table. */
483+ PyDictObject od_dict ; /* the underlying dict */
484+ _ODictNode * od_first ; /* first node in the linked list, if any */
485+ _ODictNode * od_last ; /* last node in the linked list, if any */
486+ /* od_size and od_fast_nodes are managed by _odict_resize() */
487+ Py_ssize_t od_size ; /* hash table that mirrors the dict table */
492488 _ODictNode * * od_fast_nodes ; /* managed by _odict_resize() */
493- /* od_inst_dict is OrderedDict().__dict__. */
494- PyObject * od_inst_dict ;
495- /* od_weakreflist holds weakrefs to the odict. */
496- PyObject * od_weakreflist ;
489+ size_t od_state ; /* incremented whenever the LL changes */
490+ PyObject * od_inst_dict ; /* OrderedDict().__dict__ */
491+ PyObject * od_weakreflist ; /* holds weakrefs to the odict */
497492};
498493
499494
@@ -608,6 +603,7 @@ _odict_get_index(PyODictObject *od, PyObject *key)
608603static int
609604_odict_initialize (PyODictObject * od )
610605{
606+ od -> od_state = 0 ;
611607 _odict_FIRST (od ) = NULL ;
612608 _odict_LAST (od ) = NULL ;
613609 return _odict_resize ((PyODictObject * )od );
@@ -642,6 +638,7 @@ _odict_add_head(PyODictObject *od, _ODictNode *node)
642638 _odict_FIRST (od ) = node ;
643639 _odictnode_PREV (_odict_FIRST (od )) = node ;
644640 }
641+ od -> od_state ++ ;
645642}
646643
647644static void
@@ -659,6 +656,7 @@ _odict_add_tail(PyODictObject *od, _ODictNode *node)
659656 _odictnode_NEXT (_odict_LAST (od )) = node ;
660657 _odict_LAST (od ) = node ;
661658 }
659+ od -> od_state ++ ;
662660}
663661
664662/* adds the node to the end of the list */
@@ -725,6 +723,7 @@ _odict_remove_node(PyODictObject *od, _ODictNode *node)
725723
726724 _odictnode_PREV (node ) = NULL ;
727725 _odictnode_NEXT (node ) = NULL ;
726+ od -> od_state ++ ;
728727}
729728
730729static _ODictNode *
@@ -1829,6 +1828,7 @@ typedef struct {
18291828 int kind ;
18301829 PyODictObject * di_odict ;
18311830 Py_ssize_t di_size ;
1831+ size_t di_state ;
18321832 PyObject * di_current ;
18331833 PyObject * di_result ; /* reusable result tuple for iteritems */
18341834} odictiterobject ;
@@ -1869,6 +1869,11 @@ odictiter_nextkey(odictiterobject *di)
18691869 goto done ; /* We're already done. */
18701870
18711871 /* Check for unsupported changes. */
1872+ if (di -> di_odict -> od_state != di -> di_state ) {
1873+ PyErr_SetString (PyExc_RuntimeError ,
1874+ "OrderedDict mutated during iteration" );
1875+ goto done ;
1876+ }
18721877 if (di -> di_size != PyODict_SIZE (di -> di_odict )) {
18731878 PyErr_SetString (PyExc_RuntimeError ,
18741879 "OrderedDict changed size during iteration" );
@@ -2075,6 +2080,7 @@ odictiter_new(PyODictObject *od, int kind)
20752080 di -> di_current = node ? _odictnode_KEY (node ) : NULL ;
20762081 Py_XINCREF (di -> di_current );
20772082 di -> di_size = PyODict_SIZE (od );
2083+ di -> di_state = od -> od_state ;
20782084 di -> di_odict = od ;
20792085 Py_INCREF (od );
20802086
0 commit comments