File tree Expand file tree Collapse file tree 3 files changed +30
-2
lines changed
Expand file tree Collapse file tree 3 files changed +30
-2
lines changed Original file line number Diff line number Diff line change 1+ Fixed a rare TOC/TOU bug in `trio.lowlevel.Task.iter_await_frames ` where
2+ the underlying coroutine has already been closed.
Original file line number Diff line number Diff line change @@ -1588,11 +1588,13 @@ def print_stack_for_task(task):
15881588 while coro is not None :
15891589 if hasattr (coro , "cr_frame" ):
15901590 # A real coroutine
1591- yield coro .cr_frame , coro .cr_frame .f_lineno
1591+ if cr_frame := coro .cr_frame : # TOCTOU-safe check for None
1592+ yield cr_frame , cr_frame .f_lineno
15921593 coro = coro .cr_await
15931594 elif hasattr (coro , "gi_frame" ):
15941595 # A generator decorated with @types.coroutine
1595- yield coro .gi_frame , coro .gi_frame .f_lineno
1596+ if gi_frame := coro .gi_frame : # TOCTOU-safe check for None
1597+ yield gi_frame , gi_frame .f_lineno
15961598 coro = coro .gi_yieldfrom
15971599 elif coro .__class__ .__name__ in [
15981600 "async_generator_athrow" ,
Original file line number Diff line number Diff line change @@ -3005,3 +3005,27 @@ async def main() -> None:
30053005 await _core .wait_task_rescheduled (inner_abort )
30063006
30073007 _core .run (main )
3008+
3009+
3010+ async def test_closed_task_iter_await_frames () -> None :
3011+ """Test that Task.__iter__ handles cr_frame/gi_frame becoming None.
3012+
3013+ When a coroutine completes, its cr_frame/gi_frame attributes become None.
3014+ The iterator should handle this gracefully rather than trying to access
3015+ attributes on None.
3016+ """
3017+ completed_task = None
3018+
3019+ async with _core .open_nursery () as nursery :
3020+
3021+ async def capture_task () -> None :
3022+ nonlocal completed_task
3023+ completed_task = _core .current_task ()
3024+ await _core .checkpoint ()
3025+
3026+ nursery .start_soon (capture_task )
3027+
3028+ # Task has completed, so coro.cr_frame should be None, thus no frames
3029+ assert completed_task is not None
3030+ assert completed_task .coro .cr_frame is None
3031+ assert list (completed_task .iter_await_frames ()) == []
You can’t perform that action at this time.
0 commit comments