Skip to content

Commit

Permalink
Fix refleak tests.
Browse files Browse the repository at this point in the history
Revert back to Py_DECREF() instead of the Py_SET_REFCNT(dict, 0) and fix
check that this thread owns the only reference to the dict. That ensures
that the final Py_DECREF call immediately frees the dict instead of
possibly enqueuing it to be merged.
  • Loading branch information
colesbury committed Feb 8, 2024
1 parent 459638f commit 51c6625
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 3 deletions.
19 changes: 16 additions & 3 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5989,6 +5989,18 @@ _PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
return make_dict_from_instance_attributes(interp, keys, values);
}

static bool
has_unique_reference(PyObject *op)
{
#ifdef Py_GIL_DISABLED
return (_Py_IsOwnedByCurrentThread(op) &&
op->ob_ref_local == 1 &&
_Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0);
#else
return Py_REFCNT(op) == 1;
#endif
}

// Return true if the dict was dematerialized, false otherwise.
bool
_PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv)
Expand All @@ -6005,7 +6017,9 @@ _PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv)
return false;
}
assert(_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HEAPTYPE));
if (dict->ma_keys != CACHED_KEYS(Py_TYPE(obj)) || Py_REFCNT(dict) != 1) {
if (dict->ma_keys != CACHED_KEYS(Py_TYPE(obj)) ||
!has_unique_reference((PyObject *)dict))
{
return false;
}
assert(dict->ma_values);
Expand All @@ -6016,8 +6030,7 @@ _PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv)
// Don't try this at home, kids:
dict->ma_keys = NULL;
dict->ma_values = NULL;
Py_SET_REFCNT(dict, 0);
_Py_Dealloc((PyObject *)dict);
Py_DECREF(dict);
return true;
}

Expand Down
3 changes: 3 additions & 0 deletions Python/gc_free_threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ merge_queued_objects(_PyThreadStateImpl *tstate, struct collection_state *state)
// non-GC objects here. Add one to the refcount so that we can
// decref and deallocate the object once we start the world again.
op->ob_ref_shared += (1 << _Py_REF_SHARED_SHIFT);
#ifdef Py_REF_DEBUG
_Py_IncRefTotal(_PyInterpreterState_GET());
#endif
worklist_push(&state->objs_to_decref, op);
}
}
Expand Down

0 comments on commit 51c6625

Please sign in to comment.