bpo-20526: Fix PyThreadState_Clear(): don't decref frame (GH-19120) (… · python/cpython@d1c0989 (original) (raw)
File tree
3 files changed
lines changed
- Misc/NEWS.d/next/Core and Builtins
3 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -216,6 +216,7 @@ typedef struct _ts { | ||
216 | 216 | struct _ts *next; |
217 | 217 | PyInterpreterState *interp; |
218 | 218 | |
219 | +/* Borrowed reference to the current frame (it can be NULL) */ | |
219 | 220 | struct _frame *frame; |
220 | 221 | int recursion_depth; |
221 | 222 | char overflowed; /* The stack has overflowed. Allow 50 more calls |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
1 | +Fix :c:func:`PyThreadState_Clear()`. ``PyThreadState.frame`` is a borrowed | |
2 | +reference, not a strong reference: ``PyThreadState_Clear()`` must not call | |
3 | +``Py_CLEAR(tstate->frame)``. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -566,11 +566,19 @@ _PyState_ClearModules(void) | ||
566 | 566 | void |
567 | 567 | PyThreadState_Clear(PyThreadState *tstate) |
568 | 568 | { |
569 | -if (Py_VerboseFlag && tstate->frame != NULL) | |
569 | +if (Py_VerboseFlag && tstate->frame != NULL) { | |
570 | +/* bpo-20526: After the main thread calls | |
571 | + _PyRuntimeState_SetFinalizing() in Py_FinalizeEx(), threads must | |
572 | + exit when trying to take the GIL. If a thread exit in the middle of | |
573 | + _PyEval_EvalFrameDefault(), tstate->frame is not reset to its | |
574 | + previous value. It is more likely with daemon threads, but it can | |
575 | + happen with regular threads if threading._shutdown() fails | |
576 | + (ex: interrupted by CTRL+C). */ | |
570 | 577 | fprintf(stderr, |
571 | 578 | "PyThreadState_Clear: warning: thread still has a frame\n"); |
579 | + } | |
572 | 580 | |
573 | -Py_CLEAR(tstate->frame); | |
581 | +/* Don't clear tstate->frame: it is a borrowed reference */ | |
574 | 582 | |
575 | 583 | Py_CLEAR(tstate->dict); |
576 | 584 | Py_CLEAR(tstate->async_exc); |