Skip to content

Commit 13024ef

Browse files
[7.4.x] Fix for operation on closed file in faulthandler teardown (#11631)
Co-authored-by: Simon Blanchard <[email protected]>
1 parent a40dacf commit 13024ef

File tree

2 files changed

+15
-6
lines changed

2 files changed

+15
-6
lines changed

changelog/11572.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Handle an edge case where :data:`sys.stderr` and :data:`sys.__stderr__` might already be closed when :ref:`faulthandler` is tearing down.

src/_pytest/faulthandler.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from _pytest.stash import StashKey
1010

1111

12+
fault_handler_original_stderr_fd_key = StashKey[int]()
1213
fault_handler_stderr_fd_key = StashKey[int]()
13-
fault_handler_originally_enabled_key = StashKey[bool]()
1414

1515

1616
def pytest_addoption(parser: Parser) -> None:
@@ -24,8 +24,15 @@ def pytest_addoption(parser: Parser) -> None:
2424
def pytest_configure(config: Config) -> None:
2525
import faulthandler
2626

27-
config.stash[fault_handler_stderr_fd_key] = os.dup(get_stderr_fileno())
28-
config.stash[fault_handler_originally_enabled_key] = faulthandler.is_enabled()
27+
# at teardown we want to restore the original faulthandler fileno
28+
# but faulthandler has no api to return the original fileno
29+
# so here we stash the stderr fileno to be used at teardown
30+
# sys.stderr and sys.__stderr__ may be closed or patched during the session
31+
# so we can't rely on their values being good at that point (#11572).
32+
stderr_fileno = get_stderr_fileno()
33+
if faulthandler.is_enabled():
34+
config.stash[fault_handler_original_stderr_fd_key] = stderr_fileno
35+
config.stash[fault_handler_stderr_fd_key] = os.dup(stderr_fileno)
2936
faulthandler.enable(file=config.stash[fault_handler_stderr_fd_key])
3037

3138

@@ -37,9 +44,10 @@ def pytest_unconfigure(config: Config) -> None:
3744
if fault_handler_stderr_fd_key in config.stash:
3845
os.close(config.stash[fault_handler_stderr_fd_key])
3946
del config.stash[fault_handler_stderr_fd_key]
40-
if config.stash.get(fault_handler_originally_enabled_key, False):
41-
# Re-enable the faulthandler if it was originally enabled.
42-
faulthandler.enable(file=get_stderr_fileno())
47+
# Re-enable the faulthandler if it was originally enabled.
48+
if fault_handler_original_stderr_fd_key in config.stash:
49+
faulthandler.enable(config.stash[fault_handler_original_stderr_fd_key])
50+
del config.stash[fault_handler_original_stderr_fd_key]
4351

4452

4553
def get_stderr_fileno() -> int:

0 commit comments

Comments
 (0)