@@ -7150,7 +7150,8 @@ try_set_dict_inline_only_or_other_dict(PyObject *obj, PyObject *new_dict, PyDict
7150
7150
(PyDictObject * )Py_XNewRef (new_dict ));
7151
7151
replaced = true;
7152
7152
goto exit_lock ;
7153
- } else {
7153
+ }
7154
+ else {
7154
7155
// We have inline values, we need to lock the dict and the object
7155
7156
// at the same time to safely dematerialize them. To do that while releasing
7156
7157
// the object lock we need a strong reference to the current dictionary.
@@ -7166,38 +7167,37 @@ try_set_dict_inline_only_or_other_dict(PyObject *obj, PyObject *new_dict, PyDict
7166
7167
// and replaced it with another dictionary though.
7167
7168
static int
7168
7169
replace_dict_probably_inline_materialized (PyObject * obj , PyDictObject * inline_dict ,
7169
- PyObject * new_dict , bool clear ,
7170
- PyDictObject * * replaced_dict )
7170
+ PyDictObject * cur_dict , PyObject * new_dict )
7171
7171
{
7172
- // But we could have had another thread race in after we released
7173
- // the object lock
7174
- int err = 0 ;
7175
- * replaced_dict = _PyObject_GetManagedDict (obj );
7176
- assert (FT_ATOMIC_LOAD_PTR_RELAXED (inline_dict -> ma_values ) == _PyObject_InlineValues (obj ));
7172
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (obj );
7173
+
7174
+ if (cur_dict == inline_dict ) {
7175
+ assert (FT_ATOMIC_LOAD_PTR_RELAXED (inline_dict -> ma_values ) == _PyObject_InlineValues (obj ));
7177
7176
7178
- if (* replaced_dict == inline_dict ) {
7179
- err = _PyDict_DetachFromObject (inline_dict , obj );
7177
+ int err = _PyDict_DetachFromObject (inline_dict , obj );
7180
7178
if (err != 0 ) {
7181
7179
return err ;
7182
7180
}
7183
- // We incref'd the inline dict and the object owns a ref.
7184
- // Clear the object's reference, we'll clear the local
7185
- // reference after releasing the lock.
7186
- if (clear ) {
7187
- Py_XDECREF ((PyObject * )* replaced_dict );
7188
- } else {
7189
- _PyObject_XDecRefDelayed ((PyObject * )* replaced_dict );
7190
- }
7191
- * replaced_dict = NULL ;
7192
7181
}
7193
7182
7194
7183
FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict ,
7195
- (PyDictObject * )Py_XNewRef (new_dict ));
7196
- return err ;
7184
+ (PyDictObject * )Py_XNewRef (new_dict ));
7185
+ return 0 ;
7197
7186
}
7198
7187
7199
7188
#endif
7200
7189
7190
+ static void
7191
+ decref_maybe_delay (PyObject * obj , bool delay )
7192
+ {
7193
+ if (delay ) {
7194
+ _PyObject_XDecRefDelayed (obj );
7195
+ }
7196
+ else {
7197
+ Py_XDECREF (obj );
7198
+ }
7199
+ }
7200
+
7201
7201
static int
7202
7202
set_or_clear_managed_dict (PyObject * obj , PyObject * new_dict , bool clear )
7203
7203
{
@@ -7213,32 +7213,37 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
7213
7213
// values. We need to lock both the object and the dict at the
7214
7214
// same time to safely replace it. We can't merely lock the dictionary
7215
7215
// while the object is locked because it could suspend the object lock.
7216
- PyDictObject * replaced_dict ;
7216
+ PyDictObject * cur_dict ;
7217
7217
7218
7218
assert (prev_dict != NULL );
7219
7219
Py_BEGIN_CRITICAL_SECTION2 (obj , prev_dict );
7220
7220
7221
- err = replace_dict_probably_inline_materialized (obj , prev_dict , new_dict ,
7222
- clear , & replaced_dict );
7221
+ // We could have had another thread race in between the call to
7222
+ // try_set_dict_inline_only_or_other_dict where we locked the object
7223
+ // and when we unlocked and re-locked the dictionary.
7224
+ cur_dict = _PyObject_GetManagedDict (obj );
7225
+
7226
+ err = replace_dict_probably_inline_materialized (obj , prev_dict ,
7227
+ cur_dict , new_dict );
7223
7228
7224
7229
Py_END_CRITICAL_SECTION2 ();
7225
7230
7226
- Py_DECREF (prev_dict );
7231
+ // Decref for the dictionary we incref'd in try_set_dict_inline_only_or_other_dict
7232
+ // while the object was locked
7233
+ decref_maybe_delay ((PyObject * )prev_dict ,
7234
+ !clear && prev_dict != cur_dict );
7227
7235
if (err != 0 ) {
7228
7236
return err ;
7229
7237
}
7230
- prev_dict = replaced_dict ;
7238
+
7239
+ prev_dict = cur_dict ;
7231
7240
}
7232
7241
7233
7242
if (prev_dict != NULL ) {
7234
- // Readers from the old dictionary use a borrowed reference. We need
7235
- // to set the decref the dict at the next safe point.
7236
- if (clear ) {
7237
- Py_XDECREF ((PyObject * )prev_dict );
7238
- } else {
7239
- _PyObject_XDecRefDelayed ((PyObject * )prev_dict );
7240
- }
7243
+ // decref for the dictionary that we replaced
7244
+ decref_maybe_delay ((PyObject * )prev_dict , !clear );
7241
7245
}
7246
+
7242
7247
return 0 ;
7243
7248
#else
7244
7249
PyDictObject * dict = _PyObject_GetManagedDict (obj );
@@ -7265,11 +7270,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
7265
7270
(PyDictObject * )Py_XNewRef (new_dict ));
7266
7271
7267
7272
Py_END_CRITICAL_SECTION ();
7268
- if (clear ) {
7269
- Py_XDECREF ((PyObject * )dict );
7270
- } else {
7271
- _PyObject_XDecRefDelayed ((PyObject * )dict );
7272
- }
7273
+ decref_maybe_delay ((PyObject * )dict , !clear );
7273
7274
}
7274
7275
assert (_PyObject_InlineValuesConsistencyCheck (obj ));
7275
7276
return err ;
0 commit comments