@@ -214,6 +214,15 @@ set_values(PyDictObject *mp, PyDictValues *values)
214214 _Py_atomic_store_ptr_release (& mp -> ma_values , values );
215215}
216216
217+ // gh-151593: The _Py_LOCK_DONT_DETACH flag ensures that the outer critical
218+ // section is not dropped if there is some contention on the keys lock.
219+ // It also means that it will be important that LOCK_KEYS() is essentially the
220+ // "inner-most" code and that we don't call Py_DECREF() or similar while
221+ // holding the keys lock.
222+ //
223+ // We are not allowed to acquire other locks within LOCK_KEYS(). For example,
224+ // PyType_Modified() must not be called within LOCK_KEYS() since it acquires
225+ // the type lock.
217226#define LOCK_KEYS (keys ) PyMutex_LockFlags(&keys->dk_mutex, _Py_LOCK_DONT_DETACH)
218227#define UNLOCK_KEYS (keys ) PyMutex_Unlock(&keys->dk_mutex)
219228
@@ -1923,12 +1932,13 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
19231932 }
19241933#endif
19251934
1935+ bool inserted = false;
19261936 LOCK_KEYS (keys );
19271937 ix = unicodekeys_lookup_unicode (keys , key , hash );
19281938 if (ix == DKIX_EMPTY && keys -> dk_usable > 0 ) {
19291939 // Insert into new slot
1940+ inserted = true;
19301941 FT_ATOMIC_STORE_UINT32_RELAXED (keys -> dk_version , 0 );
1931- _PyDict_SplitKeysInvalidated (keys );
19321942 Py_ssize_t hashpos = find_empty_slot (keys , hash );
19331943 ix = keys -> dk_nentries ;
19341944 dictkeys_set_index (keys , hashpos , ix );
@@ -1938,6 +1948,13 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
19381948 }
19391949 assert (ix < SHARED_KEYS_MAX_SIZE );
19401950 UNLOCK_KEYS (keys );
1951+
1952+ if (inserted ) {
1953+ // gh-151593: Calling PyType_Modified() with LOCK_KEYS() creates a
1954+ // deadlock. So only call the function after UNLOCK_KEYS().
1955+ _PyDict_SplitKeysInvalidated (keys );
1956+ }
1957+
19411958 return ix ;
19421959}
19431960
0 commit comments