diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index a715e725a7e..9fab17684ee 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -235,6 +235,28 @@ class ReprTest(unittest.TestCase): r"^$" % (file_repr, offset + 5)) +class TestIncompleteFrameAreInvisible(unittest.TestCase): + + def test_issue95818(self): + #See GH-95818 for details + import gc + self.addCleanup(gc.set_threshold, *gc.get_threshold()) + + gc.set_threshold(1,1,1) + class GCHello: + def __del__(self): + print("Destroyed from gc") + + def gen(): + yield + + fd = open(__file__) + l = [fd, GCHello()] + l.append(l) + del fd + del l + gen() + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-11-11-01-56.gh-issue-95818.iClLdl.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-11-11-01-56.gh-issue-95818.iClLdl.rst new file mode 100644 index 00000000000..1e243f5614f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-11-11-01-56.gh-issue-95818.iClLdl.rst @@ -0,0 +1 @@ +Skip over incomplete frames in :c:func:`PyThreadState_GetFrame`. diff --git a/Python/pystate.c b/Python/pystate.c index 11cc122185f..bcdb825a862 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1255,10 +1255,14 @@ PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) { assert(tstate != NULL); - if (tstate->cframe->current_frame == NULL) { + _PyInterpreterFrame *f = tstate->cframe->current_frame; + while (f && _PyFrame_IsIncomplete(f)) { + f = f->previous; + } + if (f == NULL) { return NULL; } - PyFrameObject *frame = _PyFrame_GetFrameObject(tstate->cframe->current_frame); + PyFrameObject *frame = _PyFrame_GetFrameObject(f); if (frame == NULL) { PyErr_Clear(); }