@@ -165,6 +165,8 @@ ASSERT_DICT_LOCKED(PyObject *op)
165165
166166#define IS_DICT_SHARED (mp ) _PyObject_GC_IS_SHARED(mp)
167167#define SET_DICT_SHARED (mp ) _PyObject_GC_SET_SHARED(mp)
168+ #define IS_DICT_SHARED_INLINE (mp ) _PyObject_GC_IS_SHARED_INLINE(mp)
169+ #define SET_DICT_SHARED_INLINE (mp ) _PyObject_GC_SET_SHARED_INLINE(mp)
168170#define LOAD_INDEX (keys , size , idx ) _Py_atomic_load_int##size##_relaxed(&((const int##size##_t*)keys->dk_indices)[idx]);
169171#define STORE_INDEX (keys , size , idx , value ) _Py_atomic_store_int##size##_relaxed(&((int##size##_t*)keys->dk_indices)[idx], (int##size##_t)value);
170172#define ASSERT_OWNED_OR_SHARED (mp ) \
@@ -245,6 +247,8 @@ static inline void split_keys_entry_added(PyDictKeysObject *keys)
245247#define UNLOCK_KEYS_IF_SPLIT (keys , kind )
246248#define IS_DICT_SHARED (mp ) (false)
247249#define SET_DICT_SHARED (mp )
250+ #define IS_DICT_SHARED_INLINE (mp ) (false)
251+ #define SET_DICT_SHARED_INLINE (mp )
248252#define LOAD_INDEX (keys , size , idx ) ((const int##size##_t*)(keys->dk_indices))[idx]
249253#define STORE_INDEX (keys , size , idx , value ) ((int##size##_t*)(keys->dk_indices))[idx] = (int##size##_t)value
250254
@@ -3082,20 +3086,21 @@ dict_dealloc(PyObject *self)
30823086 /* bpo-31095: UnTrack is needed before calling any callbacks */
30833087 PyObject_GC_UnTrack (mp );
30843088 Py_TRASHCAN_BEGIN (mp , dict_dealloc )
3089+ bool is_shared = IS_DICT_SHARED_INLINE (self );
30853090 if (values != NULL ) {
30863091 if (values -> embedded == 0 ) {
30873092 for (i = 0 , n = mp -> ma_keys -> dk_nentries ; i < n ; i ++ ) {
30883093 Py_XDECREF (values -> values [i ]);
30893094 }
3090- free_values (values , false );
3095+ free_values (values , is_shared );
30913096 }
3092- dictkeys_decref (interp , keys , false );
3097+ dictkeys_decref (interp , keys , is_shared );
30933098 }
30943099 else if (keys != NULL ) {
30953100 assert (keys -> dk_refcnt == 1 || keys == Py_EMPTY_KEYS );
3096- dictkeys_decref (interp , keys , false );
3101+ dictkeys_decref (interp , keys , is_shared );
30973102 }
3098- if (Py_IS_TYPE (mp , & PyDict_Type )) {
3103+ if (Py_IS_TYPE (mp , & PyDict_Type ) && ! is_shared ) {
30993104 _Py_FREELIST_FREE (dicts , mp , Py_TYPE (mp )-> tp_free );
31003105 }
31013106 else {
@@ -7047,6 +7052,9 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
70477052 FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict ,
70487053 (PyDictObject * )Py_XNewRef (new_dict ));
70497054 }
7055+ // We could be racing with a read from a borrowed reference of
7056+ // the dict, so we need to free it using QSBR.
7057+ SET_DICT_SHARED_INLINE (dict );
70507058 Py_END_CRITICAL_SECTION2 ();
70517059
70527060 if (err == 0 ) {
0 commit comments