Skip to content

Commit

Permalink
[7.4.x] Fix for operation on closed file in faulthandler teardown (#1…
Browse files Browse the repository at this point in the history
…1631)

Co-authored-by: Simon Blanchard <bnomis@gmail.com>
  • Loading branch information
github-actions[bot] and bnomis authored Nov 22, 2023
1 parent a40dacf commit 13024ef
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 6 deletions.
1 change: 1 addition & 0 deletions changelog/11572.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Handle an edge case where :data:`sys.stderr` and :data:`sys.__stderr__` might already be closed when :ref:`faulthandler` is tearing down.
20 changes: 14 additions & 6 deletions src/_pytest/faulthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
from _pytest.stash import StashKey


fault_handler_original_stderr_fd_key = StashKey[int]()
fault_handler_stderr_fd_key = StashKey[int]()
fault_handler_originally_enabled_key = StashKey[bool]()


def pytest_addoption(parser: Parser) -> None:
Expand All @@ -24,8 +24,15 @@ def pytest_addoption(parser: Parser) -> None:
def pytest_configure(config: Config) -> None:
import faulthandler

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


Expand All @@ -37,9 +44,10 @@ def pytest_unconfigure(config: Config) -> None:
if fault_handler_stderr_fd_key in config.stash:
os.close(config.stash[fault_handler_stderr_fd_key])
del config.stash[fault_handler_stderr_fd_key]
if config.stash.get(fault_handler_originally_enabled_key, False):
# Re-enable the faulthandler if it was originally enabled.
faulthandler.enable(file=get_stderr_fileno())
# Re-enable the faulthandler if it was originally enabled.
if fault_handler_original_stderr_fd_key in config.stash:
faulthandler.enable(config.stash[fault_handler_original_stderr_fd_key])
del config.stash[fault_handler_original_stderr_fd_key]


def get_stderr_fileno() -> int:
Expand Down

0 comments on commit 13024ef

Please sign in to comment.