@@ -165,6 +165,8 @@ ASSERT_DICT_LOCKED(PyObject *op)
165
165
166
166
#define IS_DICT_SHARED (mp ) _PyObject_GC_IS_SHARED(mp)
167
167
#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)
168
170
#define LOAD_INDEX (keys , size , idx ) _Py_atomic_load_int##size##_relaxed(&((const int##size##_t*)keys->dk_indices)[idx]);
169
171
#define STORE_INDEX (keys , size , idx , value ) _Py_atomic_store_int##size##_relaxed(&((int##size##_t*)keys->dk_indices)[idx], (int##size##_t)value);
170
172
#define ASSERT_OWNED_OR_SHARED (mp ) \
@@ -245,6 +247,8 @@ static inline void split_keys_entry_added(PyDictKeysObject *keys)
245
247
#define UNLOCK_KEYS_IF_SPLIT (keys , kind )
246
248
#define IS_DICT_SHARED (mp ) (false)
247
249
#define SET_DICT_SHARED (mp )
250
+ #define IS_DICT_SHARED_INLINE (mp ) (false)
251
+ #define SET_DICT_SHARED_INLINE (mp )
248
252
#define LOAD_INDEX (keys , size , idx ) ((const int##size##_t*)(keys->dk_indices))[idx]
249
253
#define STORE_INDEX (keys , size , idx , value ) ((int##size##_t*)(keys->dk_indices))[idx] = (int##size##_t)value
250
254
@@ -3082,20 +3086,21 @@ dict_dealloc(PyObject *self)
3082
3086
/* bpo-31095: UnTrack is needed before calling any callbacks */
3083
3087
PyObject_GC_UnTrack (mp );
3084
3088
Py_TRASHCAN_BEGIN (mp , dict_dealloc )
3089
+ bool is_shared = IS_DICT_SHARED_INLINE (self );
3085
3090
if (values != NULL ) {
3086
3091
if (values -> embedded == 0 ) {
3087
3092
for (i = 0 , n = mp -> ma_keys -> dk_nentries ; i < n ; i ++ ) {
3088
3093
Py_XDECREF (values -> values [i ]);
3089
3094
}
3090
- free_values (values , false );
3095
+ free_values (values , is_shared );
3091
3096
}
3092
- dictkeys_decref (interp , keys , false );
3097
+ dictkeys_decref (interp , keys , is_shared );
3093
3098
}
3094
3099
else if (keys != NULL ) {
3095
3100
assert (keys -> dk_refcnt == 1 || keys == Py_EMPTY_KEYS );
3096
- dictkeys_decref (interp , keys , false );
3101
+ dictkeys_decref (interp , keys , is_shared );
3097
3102
}
3098
- if (Py_IS_TYPE (mp , & PyDict_Type )) {
3103
+ if (Py_IS_TYPE (mp , & PyDict_Type ) && ! is_shared ) {
3099
3104
_Py_FREELIST_FREE (dicts , mp , Py_TYPE (mp )-> tp_free );
3100
3105
}
3101
3106
else {
@@ -7047,6 +7052,9 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
7047
7052
FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict ,
7048
7053
(PyDictObject * )Py_XNewRef (new_dict ));
7049
7054
}
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 );
7050
7058
Py_END_CRITICAL_SECTION2 ();
7051
7059
7052
7060
if (err == 0 ) {
0 commit comments