@@ -1251,36 +1251,52 @@ OrderedDict_copy_impl(PyObject *od)
12511251 if (od_copy == NULL )
12521252 return NULL ;
12531253
1254+ /* The loop body may run arbitrary Python code which could mutate od and
1255+ free its nodes (gh-148660); detect that the same way __eq__ does. */
1256+ size_t state = _PyODictObject_CAST (od )-> od_state ;
1257+
12541258 if (PyODict_CheckExact (od )) {
12551259 _odict_FOREACH (od , node ) {
1256- PyObject * key = _odictnode_KEY (node );
1257- PyObject * value = _odictnode_VALUE (node , od );
1260+ PyObject * key = Py_NewRef (_odictnode_KEY (node ));
1261+ Py_hash_t hash = _odictnode_HASH (node );
1262+ PyObject * value = PyODict_GetItemWithError (od , key );
12581263 if (value == NULL ) {
12591264 if (!PyErr_Occurred ())
12601265 PyErr_SetObject (PyExc_KeyError , key );
1266+ Py_DECREF (key );
12611267 goto fail ;
12621268 }
1263- if (_PyODict_SetItem_KnownHash_LockHeld ((PyObject * )od_copy , key , value ,
1264- _odictnode_HASH (node )) != 0 )
1269+ int res = _PyODict_SetItem_KnownHash_LockHeld ((PyObject * )od_copy ,
1270+ key , value , hash );
1271+ Py_DECREF (key );
1272+ if (res != 0 )
12651273 goto fail ;
1274+ if (_PyODictObject_CAST (od )-> od_state != state )
1275+ goto mutated ;
12661276 }
12671277 }
12681278 else {
12691279 _odict_FOREACH (od , node ) {
1270- int res ;
1271- PyObject * value = PyObject_GetItem (( PyObject * ) od ,
1272- _odictnode_KEY ( node ));
1273- if ( value == NULL )
1280+ PyObject * key = Py_NewRef ( _odictnode_KEY ( node )) ;
1281+ PyObject * value = PyObject_GetItem (od , key );
1282+ if ( value == NULL ) {
1283+ Py_DECREF ( key );
12741284 goto fail ;
1275- res = PyObject_SetItem (( PyObject * ) od_copy ,
1276- _odictnode_KEY ( node ) , value );
1285+ }
1286+ int res = PyObject_SetItem (( PyObject * ) od_copy , key , value );
12771287 Py_DECREF (value );
1288+ Py_DECREF (key );
12781289 if (res != 0 )
12791290 goto fail ;
1291+ if (_PyODictObject_CAST (od )-> od_state != state )
1292+ goto mutated ;
12801293 }
12811294 }
12821295 return od_copy ;
12831296
1297+ mutated :
1298+ PyErr_SetString (PyExc_RuntimeError ,
1299+ "OrderedDict mutated during iteration" );
12841300fail :
12851301 Py_DECREF (od_copy );
12861302 return NULL ;
0 commit comments