summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-03-19 18:48:25 (GMT)
committerGitHub <noreply@github.com>2020-03-19 18:48:25 (GMT)
commita36adfa6bbf5e612a4d4639124502135690899b8 (patch)
treecdd1ee17b4d00a0f51a92429f59ebe7425c82890
parentc691f209523e20797c7b696c3f171b37429f5b3f (diff)
downloadcpython-a36adfa6bbf5e612a4d4639124502135690899b8.zip
cpython-a36adfa6bbf5e612a4d4639124502135690899b8.tar.gz
cpython-a36adfa6bbf5e612a4d4639124502135690899b8.tar.bz2
bpo-39877: 4th take_gil() fix for daemon threads (GH-19080)
bpo-39877, bpo-40010: Add a third tstate_must_exit() check in take_gil() to prevent using tstate which has been freed.
-rw-r--r--Python/ceval_gil.h45
1 files changed, 23 insertions, 22 deletions
diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h
index da2a1d6..b4cb599 100644
--- a/Python/ceval_gil.h
+++ b/Python/ceval_gil.h
@@ -196,8 +196,7 @@ tstate_must_exit(PyThreadState *tstate)
tstate->interp->runtime to support calls from Python daemon threads.
After Py_Finalize() has been called, tstate can be a dangling pointer:
point to PyThreadState freed memory. */
- _PyRuntimeState *runtime = &_PyRuntime;
- PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime);
+ PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime);
return (finalizing != NULL && finalizing != tstate);
}
@@ -243,20 +242,23 @@ take_gil(PyThreadState *tstate)
}
while (_Py_atomic_load_relaxed(&gil->locked)) {
- int timed_out = 0;
- unsigned long saved_switchnum;
-
- saved_switchnum = gil->switch_number;
-
+ unsigned long saved_switchnum = gil->switch_number;
unsigned long interval = (gil->interval >= 1 ? gil->interval : 1);
+ int timed_out = 0;
COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out);
+
/* If we timed out and no switch occurred in the meantime, it is time
to ask the GIL-holding thread to drop it. */
if (timed_out &&
_Py_atomic_load_relaxed(&gil->locked) &&
gil->switch_number == saved_switchnum)
{
+ if (tstate_must_exit(tstate)) {
+ MUTEX_UNLOCK(gil->mutex);
+ PyThread_exit_thread();
+ }
+
SET_GIL_DROP_REQUEST(ceval);
}
}
@@ -281,6 +283,19 @@ _ready:
MUTEX_UNLOCK(gil->switch_mutex);
#endif
+ if (tstate_must_exit(tstate)) {
+ /* bpo-36475: If Py_Finalize() has been called and tstate is not
+ the thread which called Py_Finalize(), exit immediately the
+ thread.
+
+ This code path can be reached by a daemon thread which was waiting
+ in take_gil() while the main thread called
+ wait_for_thread_shutdown() from Py_Finalize(). */
+ MUTEX_UNLOCK(gil->mutex);
+ drop_gil(ceval, ceval2, tstate);
+ PyThread_exit_thread();
+ }
+
if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {
RESET_GIL_DROP_REQUEST(ceval, ceval2);
}
@@ -293,27 +308,13 @@ _ready:
COMPUTE_EVAL_BREAKER(ceval, ceval2);
}
- int must_exit = tstate_must_exit(tstate);
-
/* Don't access tstate if the thread must exit */
- if (!must_exit && tstate->async_exc != NULL) {
+ if (tstate->async_exc != NULL) {
_PyEval_SignalAsyncExc(tstate);
}
MUTEX_UNLOCK(gil->mutex);
- if (must_exit) {
- /* bpo-36475: If Py_Finalize() has been called and tstate is not
- the thread which called Py_Finalize(), exit immediately the
- thread.
-
- This code path can be reached by a daemon thread which was waiting
- in take_gil() while the main thread called
- wait_for_thread_shutdown() from Py_Finalize(). */
- drop_gil(ceval, ceval2, tstate);
- PyThread_exit_thread();
- }
-
errno = err;
}