Skip to content

Commit 0d266cb

Browse files
committed
gh-144054: shutdown fix for deferred ref counting
When shutting down, disable deferred refcounting for all GC objects. It is important to do this also for untracked objects, which before this change were getting missed.
1 parent f84ea11 commit 0d266cb

File tree

1 file changed

+24
-0
lines changed

1 file changed

+24
-0
lines changed

Python/gc_free_threading.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,26 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
12531253
return true;
12541254
}
12551255

1256+
// Disables deferred refcounting for all GC objects during interpreter
1257+
// shutdown. The scan_heap_visitor() skips untracked objects but those
1258+
// could have deferred refcounts enabled as well. This is separated
1259+
// into a separate scan pass since we only need to do it at shutdown.
1260+
// Note that untracked GC objects are typically exact tuples but could
1261+
// also be GC objects that were never tracked or manually untracked.
1262+
static bool
1263+
scan_heap_disable_deferred(const mi_heap_t *heap, const mi_heap_area_t *area,
1264+
void *block, size_t block_size, void *args)
1265+
{
1266+
PyObject *op = op_from_block_all_gc(block, args);
1267+
if (op == NULL) {
1268+
return true;
1269+
}
1270+
if (!_Py_IsImmortal(op) && _PyObject_HasDeferredRefcount(op)) {
1271+
disable_deferred_refcounting(op);
1272+
}
1273+
return true;
1274+
}
1275+
12561276
static int
12571277
move_legacy_finalizer_reachable(struct collection_state *state);
12581278

@@ -1487,6 +1507,10 @@ deduce_unreachable_heap(PyInterpreterState *interp,
14871507
// Restores ob_tid for reachable objects.
14881508
gc_visit_heaps(interp, &scan_heap_visitor, &state->base);
14891509

1510+
if (state->reason == _Py_GC_REASON_SHUTDOWN) {
1511+
gc_visit_heaps(interp, &scan_heap_disable_deferred, &state->base);
1512+
}
1513+
14901514
if (state->legacy_finalizers.head) {
14911515
// There may be objects reachable from legacy finalizers that are in
14921516
// the unreachable set. We need to mark them as reachable.

0 commit comments

Comments
 (0)