gh-153713: Fix cross-interpreter memory leak in _xidata_release via atomic claim-and-free#153745
gh-153713: Fix cross-interpreter memory leak in _xidata_release via atomic claim-and-free#153745imabd645 wants to merge 8 commits into
Conversation
ZeroIntensity
left a comment
There was a problem hiding this comment.
It seems you mixed two fixes in this PR. Please fix that.
|
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
|
I have addressed the CI failures and pushed the fixes for the macOS race conditions and linting issues. Ready for review! |
…ndition and interp lookup race
7e535ea to
8702c0e
Compare
|
I have made the requested changes; please review again. (I have rebased the branch to drop the accidentally mixed commit, so this PR now exclusively contains the lock-free CAS fixes for gh-153713) |
|
Thanks for making the requested changes! @ZeroIntensity: please review the changes made to this pull request. |
|
This isn't lock-free. There's a mutex around the linked list. I think we can switch to a compare-exchange loop there. |
|
Have we even discussed this? There might be different solutions, jumping to AI-generated code is not the best idea. |
|
Yeah, I know. I talked with Eric a bit about this at EP this morning. We'll probably come up with a better solution at the sprints. |
Description
This PR resolves the intentional memory leak in
Python/crossinterp.cwherexidata->objis leaked if the originating interpreter is destroyed before the receiving interpreter calls_PyXIData_Release.Instead of introducing a heavy interpreter-level registry with a blocking teardown that could cause deadlocks (especially in the PEP 703 free-threaded build), this PR implements a lock-free atomic claim-and-free protocol.
Implementation Details
_Py_atomic_int statusfield to_PyXIData_t(ACTIVE,CLAIMED_BY_SENDER_TEARDOWN,RELEASED).xid_nextandxid_prevpointers to_PyXIData_t, allowing them to be linked directly toPyInterpreterState->xidata_list_headvia an O(1) splice mutex._xidata_release: The receiver attempts a compare-and-swap fromACTIVEtoRELEASED. If it wins, it proceeds exactly as before. If it loses to the sender's teardown, it skips the free and discards its reference, avoiding a double-free.Py_EndInterpreter(viaPyInterpreterState_Delete) detaches the list under the splice lock, then lock-freely iterates the orphaned data, running a CAS fromACTIVEtoCLAIMED_BY_SENDER_TEARDOWNand safely deallocating them.This guarantees exactly one side ever frees the data, and ensures no locks are held across arbitrary
free()calls that might trigger re-entrant Python code.Verification
NEWS.dblurb file.