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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user