-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
gh-134144: Fix use-after-free in zapthreads() #134145
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
base: main
Are you sure you want to change the base?
Conversation
Can't use the _Py_FOR_EACH_TSTATE_UNLOCKED macro because it will reference the just-deleted tstate in order to get the next value.
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
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.
I'm pretty sure we can drop zapthreads
entirely, because right now the assumption is that the interpreter doesn't have any threads left. Let's hold off on this until we come to a decision on what the actual behavior should be for dangling threads.
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.
LGTM
We just need a NEWS entry.
@ZeroIntensity, regarding gh-128640, I expect we'll do that too since it solves an additional problem. However, this PR is a good idea regardless.
We need a test as well, but I'm more worried about the use-case as given in the issue. |
Sorry, the issue description isn't great. The thread wasn't alive, but for (PyThreadState *tstate = interp->threads.head;
tstate != NULL;
tstate = tstate->next)
{
free(tstate);
} |
Right, I've noticed this before. In most cases, we get lucky because the initial thread is statically allocated on the interpreter state, so it doesn't actually cause UAF. It becomes an issue with something like |
It happens without the Ensure. I've updated the linked issue with a complete program (without an Ensure). So are you saying it's not supported to use a different |
Yes, and you can't have any additional threads when you call I'm fine with this fix, but my point is that it's not enough. Let's add a test and then I'll approve. |
Yeah, a test would be nice. |
Misc/NEWS.d/next/C_API/2025-05-17-14-41-21.gh-issue-134144.xVpZik.rst
Outdated
Show resolved
Hide resolved
…Zik.rst Co-authored-by: Peter Bierma <[email protected]>
Fixes #134144. This problem was introduced by #127077 which added
_Py_FOR_EACH_TSTATE_UNLOCKED
._Py_FOR_EACH_TSTATE_UNLOCKED
reads thetstate
at the end of each loop iteration to get thenext
value. When the loop body frees thetstate
, the result is always a use-after-free. It doesn't always crash (seems rare, actually), I guess it just depends what the allocator does with those pages during the rest of the tstate deletion.