-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
gh-123321: Fix Parser/myreadline.c to prevent a segfault during a multi-threaded race #123323
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
Changes from all commits
360637f
8f16d5a
1f5c558
8a8c355
ed58ecb
db92111
b991cd6
26ad6bc
03243d0
6b0b820
40efaac
fc40da3
bebc580
934e21f
0379488
fd2929c
93dd023
c083eba
cf1b274
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Prevent Parser/myreadline race condition from segfaulting on multi-threaded | ||
use. Patch by Bar Harel and Amit Wienner. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -392,9 +392,14 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) | |
} | ||
} | ||
|
||
_PyOS_ReadlineTState = tstate; | ||
Py_BEGIN_ALLOW_THREADS | ||
|
||
// GH-123321: We need to acquire the lock before setting | ||
// _PyOS_ReadlineTState and after the release of the GIL, otherwise | ||
// the variable may be nullified by a different thread or a deadlock | ||
// may occur if the GIL is taken in any sub-function. | ||
PyThread_acquire_lock(_PyOS_ReadlineLock, 1); | ||
_PyOS_ReadlineTState = tstate; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe set _PyOS_ReadlineTState while you are still holding the GIL, before Py_BEGIN_ALLOW_THREADS. It should not make a big difference, since other threads should be blocked at PyThread_acquire_lock(_PyOS_ReadlineLock, 1) :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alrighty :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we have to release the lock outside the GIL and preferably take the lock too, otherwise it deadlocks. It fails on the free-threaded as according to @colesbury the taking of the lock isn't safe outside the GIL. I'm a little confused as theoretically if it isn't safe it should fail on the normal build too but I'm not entirely sure how that works. |
||
|
||
/* This is needed to handle the unlikely case that the | ||
* interpreter is in interactive mode *and* stdin/out are not | ||
|
@@ -418,11 +423,13 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) | |
else { | ||
rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt); | ||
} | ||
Py_END_ALLOW_THREADS | ||
|
||
// gh-123321: Must set the variable and then release the lock before | ||
// taking the GIL. Otherwise a deadlock or segfault may occur. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How can a deadlock occur due to this variable not being There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Release lock then take GIL. If you set the variable before releasing the lock you segfault. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah the link you posted is exactly what I wanted to know. Thanks! |
||
_PyOS_ReadlineTState = NULL; | ||
PyThread_release_lock(_PyOS_ReadlineLock); | ||
|
||
_PyOS_ReadlineTState = NULL; | ||
Py_END_ALLOW_THREADS | ||
|
||
if (rv == NULL) | ||
return NULL; | ||
|
Uh oh!
There was an error while loading. Please reload this page.