https://github.com/python/cpython/commit/7ebe9243950e9038dbbd9ddf46d4601ad6212260
commit: 7ebe9243950e9038dbbd9ddf46d4601ad6212260
branch: main
author: Sam Gross <[email protected]>
committer: Yhg1s <[email protected]>
date: 2026-02-19T01:49:09+01:00
summary:

gh-144969: Document that the free threading GC can change ob_tid (#144972)

files:
M Include/internal/pycore_critical_section.h
M InternalDocs/garbage_collector.md

diff --git a/Include/internal/pycore_critical_section.h 
b/Include/internal/pycore_critical_section.h
index 60b6fc4a72e88f..2a2846b1296b90 100644
--- a/Include/internal/pycore_critical_section.h
+++ b/Include/internal/pycore_critical_section.h
@@ -50,6 +50,15 @@ extern "C" {
 // Asserts that the mutex for the given object is locked. The mutex must
 // be held by the top-most critical section otherwise there's the
 // possibility that the mutex would be swalled out in some code paths.
+//
+// NOTE: We use Py_REFCNT(op) != 1 instead of
+// !PyUnstable_Object_IsUniquelyReferenced(op) because the free threading
+// GC can change an object's ob_tid (it overwrites ob_tid and later
+// restores it from the mimalloc segment).  This means
+// PyUnstable_Object_IsUniquelyReferenced() may spuriously return false
+// after a GC collection, even though the thread may still have exclusive
+// access to the object.  The refcount check is a looser but still catches
+// most misuses.
 #ifdef Py_DEBUG
 
 # define _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op)                         
  \
diff --git a/InternalDocs/garbage_collector.md 
b/InternalDocs/garbage_collector.md
index a7d872f3ec4392..94e6fb05b68d6f 100644
--- a/InternalDocs/garbage_collector.md
+++ b/InternalDocs/garbage_collector.md
@@ -153,7 +153,11 @@ pointer-sized (that is, eight bytes on a 64-bit platform).
 
 The garbage collector also temporarily repurposes the `ob_tid` (thread ID)
 and `ob_ref_local` (local reference count) fields for other purposes during
-collections.
+collections.  The `ob_tid` field is later restored from the containing
+mimalloc segment data structure.  In some cases, such as when the original
+allocating thread exits, this can result in a different `ob_tid` value.
+Code should not rely on `ob_tid` being stable across operations that may
+trigger garbage collection.
 
 
 C APIs

_______________________________________________
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