docs: document BaseException limitation in _suppress_output finally block

A KeyboardInterrupt raised inside the saved_out cleanup block would
propagate past the saved_err and devnull_fd blocks, leaking those fds.
In CPython this race is not realistically triggerable — KI is delivered
between bytecodes and os.dup2 is a single atomic C syscall — so we
accept the theoretical risk rather than silencing BaseException in a
finally block.
This commit is contained in:
2026-06-16 23:41:38 +00:00
parent 25880ded91
commit 34f7985357
+5
View File
@@ -37,6 +37,11 @@ def _suppress_output():
os.dup2(devnull_fd, 2)
yield
finally:
# Each block is a separate sequential statement. A BaseException (e.g.
# KeyboardInterrupt) raised inside block N would propagate past blocks N+1
# and N+2, leaving saved_err or devnull_fd unclosed. In CPython, KI is
# delivered between bytecodes, not mid-syscall; os.dup2 is a single C call
# and completes atomically, so this race is not realistically triggerable.
if saved_out is not None:
try:
os.dup2(saved_out, 1)