Description
Bug report
Bug description:
First of all, I know exactly how this bug is going to sound: batshit insane. I implore you to keep reading.
I've had a timer application for ages that uses signal.alarm()
concurrently with input()
so that it has a rudimentary way of displaying things in the background while still allowing user interaction on the CLI. The gist of it is this:
@staticmethod
def _input_timeout(prompt, timeout_secs):
class TimeExpiredException(Exception): pass
def raise_exception(signum, frame):
raise TimeExpiredException()
signal.signal(signal.SIGALRM, raise_exception)
try:
signal.alarm(timeout_secs)
result = input(prompt)
signal.alarm(0)
except TimeExpiredException:
result = None
return result
This program has mysteriously stopped working with Python 3.13.3 with an exceptionally strange error mode: my signal handler is called from somewhere I apparently do not expect (HelpFormatter
), causing the whole process to terminate. This always happens after exactly 29 seconds when I run my process as user and after exactly 25 seconds when I run as root. It happens only when there is no __pycache__
present, i.e., when the Python bytecode is generated on startup.
I tried creating a minimal reproducer, which was super difficult. Even when I remove dead code from the Python script, the bug stops triggering. Some code removal was fine, but for example if I remove the wrapper around argparse
, the bug disappears.
As I said. This sounds batshit crazy.
When the mystery signal is caught, it gives one final indication where it comes from:
reliant [/tmp/heisenbug]: rm -fr __pycache__/ && time ./stopwatch
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Exception ignored in tp_clear of HelpFormatter:
Traceback (most recent call last):
File "/tmp/heisenbug/./stopwatch", line 69, in raise_exception
raise TimeExpiredException()
StopWatch._input_timeout.<locals>.TimeExpiredException:
FINALLY
real 0m25,035s
user 0m0,025s
sys 0m0,011s
Note the message: Exception ignored in tp_clear of HelpFormatter:
(this was running as root, you see that it took 25 seconds.)
Just so you believe me that it always triggers after the same time, here are three consecutive runs as root (I swear this is not copy paste, timings are accurate to millisecond level!):
reliant [/tmp/heisenbug]: rm -fr __pycache__/ && time ./stopwatch
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Exception ignored in tp_clear of HelpFormatter:
Traceback (most recent call last):
File "/tmp/heisenbug/./stopwatch", line 69, in raise_exception
raise TimeExpiredException()
StopWatch._input_timeout.<locals>.TimeExpiredException:
FINALLY
real 0m25,035s
user 0m0,025s
sys 0m0,011s
reliant [/tmp/heisenbug]: rm -fr __pycache__/ && time ./stopwatch
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Exception ignored in tp_clear of HelpFormatter:
Traceback (most recent call last):
File "/tmp/heisenbug/./stopwatch", line 69, in raise_exception
raise TimeExpiredException()
StopWatch._input_timeout.<locals>.TimeExpiredException:
FINALLY
real 0m25,035s
user 0m0,025s
sys 0m0,011s
reliant [/tmp/heisenbug]: rm -fr __pycache__/ && time ./stopwatch
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Exception ignored in tp_clear of HelpFormatter:
Traceback (most recent call last):
File "/tmp/heisenbug/./stopwatch", line 69, in raise_exception
raise TimeExpiredException()
StopWatch._input_timeout.<locals>.TimeExpiredException:
FINALLY
real 0m25,035s
user 0m0,025s
sys 0m0,010s
And here some runs as user:
reliant joe [/tmp/heisenbug]: rm -fr __pycache__ && time ./stopwatch
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Exception ignored in tp_clear of HelpFormatter:
Traceback (most recent call last):
File "/tmp/heisenbug/./stopwatch", line 69, in raise_exception
raise TimeExpiredException()
StopWatch._input_timeout.<locals>.TimeExpiredException:
FINALLY
real 0m29,038s
user 0m0,029s
sys 0m0,010s
reliant joe [/tmp/heisenbug]: rm -fr __pycache__ && time ./stopwatch
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Exception ignored in tp_clear of HelpFormatter:
Traceback (most recent call last):
File "/tmp/heisenbug/./stopwatch", line 69, in raise_exception
raise TimeExpiredException()
StopWatch._input_timeout.<locals>.TimeExpiredException:
FINALLY
real 0m29,039s
user 0m0,027s
sys 0m0,012s
reliant joe [/tmp/heisenbug]: rm -fr __pycache__ && time ./stopwatch
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Exception ignored in tp_clear of HelpFormatter:
Traceback (most recent call last):
File "/tmp/heisenbug/./stopwatch", line 69, in raise_exception
raise TimeExpiredException()
StopWatch._input_timeout.<locals>.TimeExpiredException:
FINALLY
real 0m29,038s
user 0m0,029s
sys 0m0,009s
I'm running on 6.14.0-15-generic #15-Ubuntu. My CPU is an AMD Ryzen Threadripper PRO 3945WX 12-Cores. I'm using the Ubuntu-provided Python package (Ubuntu calls it 3.13.3-1):
Python 3.13.3 (main, Apr 8 2025, 19:55:40) [GCC 14.2.0] on linux
I cannot reproduce this issue on Debian with Python 3.11/ARM nor on another Ubuntu with Python 3.12/x86_64.
I cannot attach files (the reproducer) to this bug, so here it is as base64:
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
3dZt3dZt3dZt3dZt3dZt3faN2v8Au7ZfrgBQAAA=
You can simply unpack it by doing:
$ openssl base64 -d | tar xvz
And pasting the above base64 blob in. Remember you have to clear __pycache__
to trigger the bug. I'm including the bytecode in case it contains something interesting.
Please someone tell me this is reproducible and I'm not completely losing my marbles.
CPython versions tested on:
3.13
Operating systems tested on:
Linux