]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-130030: Fix crash on 32-bit Linux with free threading (gh-130043)
authorSam Gross <colesbury@gmail.com>
Wed, 12 Feb 2025 23:09:15 +0000 (18:09 -0500)
committerGitHub <noreply@github.com>
Wed, 12 Feb 2025 23:09:15 +0000 (18:09 -0500)
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.

Objects/obmalloc.c
Python/gc_free_threading.c

index 5688049b02469675814f1f268ff5f59792598c39..6341251007aa8ed257db625942c6476ebf7e5f0b 100644 (file)
@@ -3297,12 +3297,12 @@ static bool _collect_alloc_stats(
 static void
 py_mimalloc_print_stats(FILE *out)
 {
-    fprintf(out, "Small block threshold = %zd, in %u size classes.\n",
-        MI_SMALL_OBJ_SIZE_MAX, MI_BIN_HUGE);
-    fprintf(out, "Medium block threshold = %zd\n",
-            MI_MEDIUM_OBJ_SIZE_MAX);
-    fprintf(out, "Large object max size = %zd\n",
-            MI_LARGE_OBJ_SIZE_MAX);
+    fprintf(out, "Small block threshold = %zu, in %u size classes.\n",
+        (size_t)MI_SMALL_OBJ_SIZE_MAX, MI_BIN_HUGE);
+    fprintf(out, "Medium block threshold = %zu\n",
+            (size_t)MI_MEDIUM_OBJ_SIZE_MAX);
+    fprintf(out, "Large object max size = %zu\n",
+            (size_t)MI_LARGE_OBJ_SIZE_MAX);
 
     mi_heap_t *heap = mi_heap_get_default();
     struct _alloc_stats stats;
index 9e459da3a4437069e02eece669a7ab0210dbe6e2..0d6fddb5705b4a1f135577944b01c65b4f5308ff 100644 (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);