You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
KeyboardInterrupt not handled while evaluating a tight while loop condition on Python 3.13 #130279
^CTraceback (most recent call last):
File "/home/harshil/test.py", line 40, in <module>
loop_1(a)
~~~~~~^^^
File "/home/harshil/test.py", line 14, in loop_1
while not a.shutdown_requested:
^^^^^^^^^^^^^^^^^^^^
KeyboardInterrupt
If you run this program on Python 3.13 (3.13.1, and 3.13.2), pressing Ctrl+C does not execute the except and finally blocks in the case of loop_1(), but it works for loop_2().
If you run the same program on 3.14a5, or below 3.13, the issue does not happen, and the print statements are visible too.
Interestingly, if you add time.sleep(0.1) inside the while loop in loop_1, this strange phenomenon will not occur. (My environment is Windows 11, Python 3.13.1)
On 3.14.7 this dies with a KeyboardInterrupt traceback pointing at if x < 0:, every run (5/5 here). Add any statement after the if (even a pass) and it prints handled.
dis shows why: the back edge of the untaken branch gets its own block, outside the try's exception table ranges:
So when the eval breaker raises at that JUMP_BACKWARD, the lookup finds no handler and the exception leaves the frame. finally blocks are skipped the same way. Injecting with PyThreadState_SetAsyncExc from another thread, I got 300/300 escapes for this shape and none for the control.
Activity
LH-and-FPGA commentedon Feb 19, 2025
Interestingly, if you add
time.sleep(0.1)inside thewhileloop inloop_1, this strange phenomenon will not occur. (My environment is Windows 11, Python 3.13.1)wilmerwang commentedon Feb 19, 2025
I think it is caused by busy wait. Maybe we can use global signal, multithreading or simulated clock interrupt.
LH-and-FPGA commentedon Feb 19, 2025
But the second one also has a busy wait, why can it still work? That's strange.
colesbury commentedon Feb 19, 2025
cc @markshannon @iritkatriel:
the
next_instris after theJUMP_BACKWARDin 3.13 when the eval breaker is checked, so it doesn't dispatch to the correct exception handler:cpython/Python/generated_cases.c.h
Lines 3600 to 3606 in 5907cd6
cpython/Python/ceval.c
Line 883 in 5907cd6
markshannon commentedon May 6, 2025
This is fixed on main, but still present in 3.13.
PawelAndruszkiewicz commentedon Mar 31, 2026
With Python 3.14.3,
loop_1(a)works, butloop_2(a)doesn't.The following:
doesn't work on either 3.13.12 or 3.14.3.
Tested on Fedora43.
t4lesss commentedon Oct 15, 2026
Still reproducible on 3.14.7 (Linux), and not only with
while: same shape asloop_2above, the loop body ends in anif.On 3.14.7 this dies with a
KeyboardInterrupttraceback pointing atif x < 0:, every run (5/5 here). Add any statement after theif(even apass) and it printshandled.disshows why: the back edge of the untaken branch gets its own block, outside the try's exception table ranges:So when the eval breaker raises at that
JUMP_BACKWARD, the lookup finds no handler and the exception leaves the frame.finallyblocks are skipped the same way. Injecting withPyThreadState_SetAsyncExcfrom another thread, I got 300/300 escapes for this shape and none for the control.— Tales
Merge branch 'main' into pythongh-130279-backward-jump-handler
Merge branch 'main' into pythongh-130279-backward-jump-handler