Skip to content

Commit

Permalink
pythongh-112529: Don't untrack tuples or dicts with zero refcount
Browse files Browse the repository at this point in the history
The free-threaded GC sometimes sees objects with zero refcount. This can
happen due to the delay in merging biased reference counting fields,
and, in the future, due to deferred reference counting. We should not
untrack these objects or they will never be collected.
  • Loading branch information
colesbury committed Mar 29, 2024
1 parent 8dbfdb2 commit d3ed5d7
Showing 1 changed file with 18 additions and 15 deletions.
33 changes: 18 additions & 15 deletions Python/gc_free_threading.c
Expand Up @@ -374,25 +374,28 @@ update_refs(const mi_heap_t *heap, const mi_heap_area_t *area,
return true;
}

// Untrack tuples and dicts as necessary in this pass.
if (PyTuple_CheckExact(op)) {
_PyTuple_MaybeUntrack(op);
if (!_PyObject_GC_IS_TRACKED(op)) {
gc_restore_refs(op);
return true;
Py_ssize_t refcount = Py_REFCNT(op);
_PyObject_ASSERT(op, refcount >= 0);

if (refcount > 0) {
// Untrack tuples and dicts as necessary in this pass, but not objects
// with zero refcount, which we will want to collect.
if (PyTuple_CheckExact(op)) {
_PyTuple_MaybeUntrack(op);
if (!_PyObject_GC_IS_TRACKED(op)) {
gc_restore_refs(op);
return true;
}
}
}
else if (PyDict_CheckExact(op)) {
_PyDict_MaybeUntrack(op);
if (!_PyObject_GC_IS_TRACKED(op)) {
gc_restore_refs(op);
return true;
else if (PyDict_CheckExact(op)) {
_PyDict_MaybeUntrack(op);
if (!_PyObject_GC_IS_TRACKED(op)) {
gc_restore_refs(op);
return true;
}
}
}

Py_ssize_t refcount = Py_REFCNT(op);
_PyObject_ASSERT(op, refcount >= 0);

// We repurpose ob_tid to compute "gc_refs", the number of external
// references to the object (i.e., from outside the GC heaps). This means
// that ob_tid is no longer a valid thread id until it is restored by
Expand Down

0 comments on commit d3ed5d7

Please sign in to comment.