-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
gh-123241: Don't modify ref count during visitation #142232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Is this limitation documented? That sounds like it should be mentioned in the docs, and a free-threading porting guide.
There's an assumption I'd like to relax eventually :) |
colesbury
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this found from a crash or by inspecting the code? Either way, I think it's worth fixing, but my understanding was that the problematic pattern involved incref/decref around the visit, i.e. something like:
Py_INCREF(obj);
Py_VISIT(obj);
Py_DECREF(obj);
While this code was more like:
Py_INCREF(obj);
Py_DECREF(obj);
Py_VISIT(obj);
I think we can make the free threaded GC less susceptible to this problem, but we should also document the things you shouldn't do in a tp_traverse handler.
Modules/_ctypes/ctypes.h
Outdated
| if (PyCType_Type == NULL) { | ||
| PyErr_Format(PyExc_TypeError, "expected a ctypes type, got '%N'", type); | ||
| return NULL; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't create exceptions (or any other object) during tp_traverse handlers either. I think this should be pulled up to the tp_dealloc / tp_clear if we want to print unraisable exceptions there.
I found this from a crash that occurred while porting the parallel GC in cinder (it can call the same traverse function from multiple threads) to 3.14. |
346043e to
f860118
Compare
Sounds good, I've gone ahead and added the Borrow version and switched to using it instead. |
|
Thanks! Looks great; I left some nitpicks in DinoV#2 |
_PyType_GetBaseByToken_Borrow can't fail; adjust comments
|
Sorry, @DinoV and @encukou, I could not cleanly backport this to |
|
Thank you! |
…honGH-142232) (cherry picked from commit da8199f) Co-authored-by: Dino Viehland <[email protected]>
|
GH-142567 is a backport of this pull request to the 3.14 branch. |
#142567) (cherry picked from commit da8199f) Co-authored-by: Dino Viehland <[email protected]>
traverse functions shouldn't modify the ref count during visitation otherwise they'll cause issues in the free threaded GC.
CType_Type_traverseuses_PyStgInfo_FromType_NoStateto get back to the state object but this causes an incref to happen viaPyType_GetBaseByToken.Instead of using
PyType_GetBaseByTokenthis just walks to find the CType's solid base. BecausePyCType_Typeadds fields and immediately descends fromPyType_Typeit will always be the base immediately beforePyType_Type.Py_INCREF()/Py_DECREF()intp_traversehandlers #123241