Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Description
Bug report
Background
The free threading GC uses two queue-like data structures to keep track of objects:
struct worklist, which is a singly linked list that repurposesob_tidfor the linked list pointer_PyObjectStack, which is effectively a dynamically sized array ofPyObject*. (Implemented using a linked list of fixed size array buffers).
Thestruct worklist data structure is convenient because enqueueing objects doesn't require a memory allocation and so can't fail. However, an object can only be part of one "worklist" at a time, because each object has only oneob_tid field.
Bug
Other threads can run while the GC isfinalizing cyclic garbage andwhile it's callingtp_clear() and other clean-up.
During that time, some thread may callgc.get_objects(), which can return otherwise "unreachable" objects. The implementation of_PyGC_GetObjects temporarily pushes objects to astruct worklist, including objects that might already be part of some other worklist, overwriting the linked list pointer. This essentially corrupts the state of the in-progress GC and causes assertion failures.
Proposed fix
- We should probably exclude objects in the "unreachable" (i.e.
_PyGC_BITS_UNREACHABLE) from being returned bygc.get_objects() - We should limit the use of
struct worklistto the actual GC and use_PyObjectStack(or some other data structure) in_PyGC_GetObjects(). This reduces the risk of bugs causing an object to be added to more than one worklist.