gh-130030: Fix crash on 32-bit Linux with free threading (gh-130043)

The `gc_get_refs` assertion needs to be after we check the alive and
unreachable bits. Otherwise, `ob_tid` may store the actual thread id
instead of the computed `gc_refs`, which may trigger the assertion if
the `ob_tid` looks like a negative value.

Also fix a few type warnings on 32-bit systems.
This commit is contained in:
Sam Gross 2025-02-12 18:09:15 -05:00 committed by GitHub
parent 791cdfe141
commit e09442089e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 13 additions and 11 deletions

View file

@ -581,11 +581,13 @@ gc_mark_buffer_len(gc_mark_args_t *args)
}
// Returns number of free entry slots in buffer
#ifndef NDEBUG
static inline unsigned int
gc_mark_buffer_avail(gc_mark_args_t *args)
{
return BUFFER_SIZE - gc_mark_buffer_len(args);
}
#endif
static inline bool
gc_mark_buffer_is_empty(gc_mark_args_t *args)
@ -1074,14 +1076,14 @@ mark_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
return true;
}
_PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0,
"refcount is too small");
if (gc_is_alive(op) || !gc_is_unreachable(op)) {
// Object was already marked as reachable.
return true;
}
_PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0,
"refcount is too small");
// GH-129236: If we've seen an active frame without a valid stack pointer,
// then we can't collect objects with deferred references because we may
// have missed some reference to the object on the stack. In that case,
@ -1178,10 +1180,10 @@ move_legacy_finalizer_reachable(struct collection_state *state);
static void
gc_prime_from_spans(gc_mark_args_t *args)
{
Py_ssize_t space = BUFFER_HI - gc_mark_buffer_len(args);
unsigned int space = BUFFER_HI - gc_mark_buffer_len(args);
// there should always be at least this amount of space
assert(space <= gc_mark_buffer_avail(args));
assert(space > 0);
assert(space <= BUFFER_HI);
gc_span_t entry = args->spans.stack[--args->spans.size];
// spans on the stack should always have one or more elements
assert(entry.start < entry.end);