Bug report
Bug description:
Very similar to #151424, but this is not about impossible stack traces but implausible. :-)
Found while wrapping my head around #151424 and checking the source code for internals of last_profiled_frame.
Mechansim
The interpr has to advance tstate->last_profiled_frame for us. It does so in _PyEval_FrameClearAndPop:
| if (tstate->last_profiled_frame != NULL && tstate->last_profiled_frame == frame) { |
But the helper not always used when a frame is removed from the chain.
Naively:
_YIELD_VALUE missed:
| frame = tstate->current_frame = frame->previous; | |
| gen_frame->previous = NULL; |
RETURN_GENERATOR missed:
| _PyThreadState_PopFrame(tstate, frame); |
_gen_throw missed:
| tstate->current_frame = prev; |
| tstate->current_frame = prev; |
frame-init fail missed:
| clear_thread_frame(tstate, frame); |
Reproduction
def gen(): while True: n = yield sum(range(n)) g = gen() next(g) def drv_a(): g.send(5000) def drv_b(): g.send(50000) while True: drv_a(); drv_b()
2026-06-13T11:41:14.582916000+0200 maurycy@gimel /Users/maurycy/work/cpython-main (main f4f1020?) % sudo ./python.exe -m profiling.sampling run --collapsed -o /tmp/stacks.txt -d 10 genrepro.py&& cat /tmp/stacks.txt Captured 10,000 samples in 10.00 seconds Sample rate: 999.99 samples/sec Error rate: 0.01 Collapsed stack output written to /tmp/stacks.txt tid:13788812;<frozen runpy>:_run_module_as_main:201;<frozen runpy>:_run_code:87;genrepro.py:<module>:13;genrepro.py:drv_b:10;genrepro.py:gen:4 9990 tid:13788812;<frozen runpy>:_run_module_as_main:201;<frozen runpy>:_run_code:87;genrepro.py:<module>:13;genrepro.py:drv_b:10;genrepro.py:gen:3 6 tid:13788812;<frozen runpy>:_run_module_as_main:201;<frozen runpy>:_run_code:87;genrepro.py:<module>:13 3 2026-06-13T11:41:27.285300000+0200 maurycy@gimel /Users/maurycy/work/cpython-main (main f4f1020?) %
Where is drv_a? TOTALLY_GONE.
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS