https://github.com/python/cpython/commit/e09442089eb86d88d4b5a96e56f713cb31173ae9
commit: e09442089eb86d88d4b5a96e56f713cb31173ae9
branch: main
author: Sam Gross <[email protected]>
committer: colesbury <[email protected]>
date: 2025-02-12T18:09:15-05:00
summary:

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.

files:
M Objects/obmalloc.c
M Python/gc_free_threading.c

diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index 5688049b024696..6341251007aa8e 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -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;
diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c
index 9e459da3a44370..0d6fddb5705b4a 100644
--- a/Python/gc_free_threading.c
+++ b/Python/gc_free_threading.c
@@ -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);

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to