@@ -188,6 +188,25 @@ static size_t opcache_global_misses = 0;
188
188
#include "pythread.h"
189
189
#include "ceval_gil.h"
190
190
191
+ static void
192
+ ensure_tstate_not_null (const char * func , PyThreadState * tstate )
193
+ {
194
+ if (tstate == NULL ) {
195
+ _Py_FatalErrorFunc (func , "current thread state is NULL" );
196
+ }
197
+ }
198
+
199
+
200
+ #ifndef NDEBUG
201
+ static int is_tstate_valid (PyThreadState * tstate )
202
+ {
203
+ assert (!_PyMem_IsPtrFreed (tstate ));
204
+ assert (!_PyMem_IsPtrFreed (tstate -> interp ));
205
+ return 1 ;
206
+ }
207
+ #endif
208
+
209
+
191
210
int
192
211
PyEval_ThreadsInitialized (void )
193
212
{
@@ -208,6 +227,7 @@ PyEval_InitThreads(void)
208
227
PyThread_init_thread ();
209
228
create_gil (gil );
210
229
PyThreadState * tstate = _PyRuntimeState_GetThreadState (runtime );
230
+ ensure_tstate_not_null (__func__ , tstate );
211
231
take_gil (ceval , tstate );
212
232
213
233
struct _pending_calls * pending = & ceval -> pending ;
@@ -235,14 +255,26 @@ _PyEval_FiniThreads(struct _ceval_runtime_state *ceval)
235
255
}
236
256
}
237
257
258
+ /* This function is designed to exit daemon threads immediately rather than
259
+ taking the GIL if Py_Finalize() has been called.
260
+
261
+ The caller must *not* hold the GIL, since this function does not release
262
+ the GIL before exiting the thread.
263
+
264
+ When this function is called by a daemon thread after Py_Finalize() has been
265
+ called, the GIL does no longer exist.
266
+
267
+ tstate must be non-NULL. */
238
268
static inline void
239
269
exit_thread_if_finalizing (PyThreadState * tstate )
240
270
{
241
- _PyRuntimeState * runtime = tstate -> interp -> runtime ;
242
- /* _Py_Finalizing is protected by the GIL */
271
+ /* bpo-39877: Access _PyRuntime directly rather than using
272
+ tstate->interp->runtime to support calls from Python daemon threads.
273
+ After Py_Finalize() has been called, tstate can be a dangling pointer:
274
+ point to PyThreadState freed memory. */
275
+ _PyRuntimeState * runtime = & _PyRuntime ;
243
276
PyThreadState * finalizing = _PyRuntimeState_GetFinalizing (runtime );
244
277
if (finalizing != NULL && finalizing != tstate ) {
245
- drop_gil (& runtime -> ceval , tstate );
246
278
PyThread_exit_thread ();
247
279
}
248
280
}
@@ -280,13 +312,14 @@ void
280
312
PyEval_AcquireLock (void )
281
313
{
282
314
_PyRuntimeState * runtime = & _PyRuntime ;
283
- struct _ceval_runtime_state * ceval = & runtime -> ceval ;
284
315
PyThreadState * tstate = _PyRuntimeState_GetThreadState (runtime );
285
- if (tstate == NULL ) {
286
- Py_FatalError ("current thread state is NULL" );
287
- }
288
- take_gil (ceval , tstate );
316
+ ensure_tstate_not_null (__func__ , tstate );
317
+
289
318
exit_thread_if_finalizing (tstate );
319
+ assert (is_tstate_valid (tstate ));
320
+
321
+ struct _ceval_runtime_state * ceval = & runtime -> ceval ;
322
+ take_gil (ceval , tstate );
290
323
}
291
324
292
325
void
@@ -304,15 +337,18 @@ PyEval_ReleaseLock(void)
304
337
void
305
338
PyEval_AcquireThread (PyThreadState * tstate )
306
339
{
307
- assert (tstate != NULL );
340
+ ensure_tstate_not_null (__func__ , tstate );
341
+
342
+ exit_thread_if_finalizing (tstate );
343
+ assert (is_tstate_valid (tstate ));
308
344
309
345
_PyRuntimeState * runtime = tstate -> interp -> runtime ;
310
346
struct _ceval_runtime_state * ceval = & runtime -> ceval ;
311
347
312
348
/* Check someone has called PyEval_InitThreads() to create the lock */
313
349
assert (gil_created (& ceval -> gil ));
350
+
314
351
take_gil (ceval , tstate );
315
- exit_thread_if_finalizing (tstate );
316
352
if (_PyThreadState_Swap (& runtime -> gilstate , tstate ) != NULL ) {
317
353
Py_FatalError ("non-NULL old thread state" );
318
354
}
@@ -344,8 +380,9 @@ _PyEval_ReInitThreads(_PyRuntimeState *runtime)
344
380
return ;
345
381
}
346
382
recreate_gil (& ceval -> gil );
347
- PyThreadState * current_tstate = _PyRuntimeState_GetThreadState (runtime );
348
- take_gil (ceval , current_tstate );
383
+ PyThreadState * tstate = _PyRuntimeState_GetThreadState (runtime );
384
+ ensure_tstate_not_null (__func__ , tstate );
385
+ take_gil (ceval , tstate );
349
386
350
387
struct _pending_calls * pending = & ceval -> pending ;
351
388
pending -> lock = PyThread_allocate_lock ();
@@ -354,7 +391,7 @@ _PyEval_ReInitThreads(_PyRuntimeState *runtime)
354
391
}
355
392
356
393
/* Destroy all threads except the current one */
357
- _PyThreadState_DeleteExcept (runtime , current_tstate );
394
+ _PyThreadState_DeleteExcept (runtime , tstate );
358
395
}
359
396
360
397
/* This function is used to signal that async exceptions are waiting to be
@@ -383,16 +420,16 @@ PyEval_SaveThread(void)
383
420
void
384
421
PyEval_RestoreThread (PyThreadState * tstate )
385
422
{
386
- assert (tstate != NULL );
423
+ ensure_tstate_not_null (__func__ , tstate );
424
+
425
+ exit_thread_if_finalizing (tstate );
426
+ assert (is_tstate_valid (tstate ));
387
427
388
428
_PyRuntimeState * runtime = tstate -> interp -> runtime ;
389
429
struct _ceval_runtime_state * ceval = & runtime -> ceval ;
390
430
assert (gil_created (& ceval -> gil ));
391
431
392
- int err = errno ;
393
432
take_gil (ceval , tstate );
394
- exit_thread_if_finalizing (tstate );
395
- errno = err ;
396
433
397
434
_PyThreadState_Swap (& runtime -> gilstate , tstate );
398
435
}
@@ -750,11 +787,14 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
750
787
PyObject * * fastlocals , * * freevars ;
751
788
PyObject * retval = NULL ; /* Return value */
752
789
_PyRuntimeState * const runtime = & _PyRuntime ;
753
- PyThreadState * const tstate = _PyRuntimeState_GetThreadState (runtime );
754
790
struct _ceval_runtime_state * const ceval = & runtime -> ceval ;
755
791
_Py_atomic_int * const eval_breaker = & ceval -> eval_breaker ;
756
792
PyCodeObject * co ;
757
793
794
+ PyThreadState * const tstate = _PyRuntimeState_GetThreadState (runtime );
795
+ ensure_tstate_not_null (__func__ , tstate );
796
+ assert (is_tstate_valid (tstate ));
797
+
758
798
/* when tracing we set things up so that
759
799
760
800
not (instr_lb <= current_bytecode_offset < instr_ub)
@@ -1242,11 +1282,11 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
1242
1282
1243
1283
/* Other threads may run now */
1244
1284
1245
- take_gil (ceval , tstate );
1246
-
1247
1285
/* Check if we should make a quick exit. */
1248
1286
exit_thread_if_finalizing (tstate );
1249
1287
1288
+ take_gil (ceval , tstate );
1289
+
1250
1290
if (_PyThreadState_Swap (& runtime -> gilstate , tstate ) != NULL ) {
1251
1291
Py_FatalError ("orphan tstate" );
1252
1292
}
0 commit comments