Skip to content

Commit e094420

Browse files
authored
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.
1 parent 791cdfe commit e094420

File tree

2 files changed

+13
-11
lines changed

2 files changed

+13
-11
lines changed

Objects/obmalloc.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -3297,12 +3297,12 @@ static bool _collect_alloc_stats(
32973297
static void
32983298
py_mimalloc_print_stats(FILE *out)
32993299
{
3300-
fprintf(out, "Small block threshold = %zd, in %u size classes.\n",
3301-
MI_SMALL_OBJ_SIZE_MAX, MI_BIN_HUGE);
3302-
fprintf(out, "Medium block threshold = %zd\n",
3303-
MI_MEDIUM_OBJ_SIZE_MAX);
3304-
fprintf(out, "Large object max size = %zd\n",
3305-
MI_LARGE_OBJ_SIZE_MAX);
3300+
fprintf(out, "Small block threshold = %zu, in %u size classes.\n",
3301+
(size_t)MI_SMALL_OBJ_SIZE_MAX, MI_BIN_HUGE);
3302+
fprintf(out, "Medium block threshold = %zu\n",
3303+
(size_t)MI_MEDIUM_OBJ_SIZE_MAX);
3304+
fprintf(out, "Large object max size = %zu\n",
3305+
(size_t)MI_LARGE_OBJ_SIZE_MAX);
33063306

33073307
mi_heap_t *heap = mi_heap_get_default();
33083308
struct _alloc_stats stats;

Python/gc_free_threading.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,13 @@ gc_mark_buffer_len(gc_mark_args_t *args)
581581
}
582582

583583
// Returns number of free entry slots in buffer
584+
#ifndef NDEBUG
584585
static inline unsigned int
585586
gc_mark_buffer_avail(gc_mark_args_t *args)
586587
{
587588
return BUFFER_SIZE - gc_mark_buffer_len(args);
588589
}
590+
#endif
589591

590592
static inline bool
591593
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,
10741076
return true;
10751077
}
10761078

1077-
_PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0,
1078-
"refcount is too small");
1079-
10801079
if (gc_is_alive(op) || !gc_is_unreachable(op)) {
10811080
// Object was already marked as reachable.
10821081
return true;
10831082
}
10841083

1084+
_PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0,
1085+
"refcount is too small");
1086+
10851087
// GH-129236: If we've seen an active frame without a valid stack pointer,
10861088
// then we can't collect objects with deferred references because we may
10871089
// 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);
11781180
static void
11791181
gc_prime_from_spans(gc_mark_args_t *args)
11801182
{
1181-
Py_ssize_t space = BUFFER_HI - gc_mark_buffer_len(args);
1183+
unsigned int space = BUFFER_HI - gc_mark_buffer_len(args);
11821184
// there should always be at least this amount of space
11831185
assert(space <= gc_mark_buffer_avail(args));
1184-
assert(space > 0);
1186+
assert(space <= BUFFER_HI);
11851187
gc_span_t entry = args->spans.stack[--args->spans.size];
11861188
// spans on the stack should always have one or more elements
11871189
assert(entry.start < entry.end);

0 commit comments

Comments
 (0)