From 357ce94fcd0af5ed8f7d20416273aa46bba97a77 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Fri, 23 Feb 2018 02:37:38 +0100 Subject: [PATCH] bpo-30028: make test.support.temp_cwd() fork-safe (GH-1066) Make test.support.temp_cwd() fork-safe. The context manager test.support.temp_cwd() no longer removes the temporary directory when executing in a process other than the parent it entered from. If a forked child exits the context manager it won't do the cleanup. (cherry picked from commit 33dddac00ba8d9b72cf21b8698504077eb3c23ad) Co-authored-by: Anselm Kruis --- Lib/test/support/__init__.py | 6 +++++- Lib/test/test_support.py | 29 +++++++++++++++++++++++++++++ Misc/ACKS | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 22868d4ba1a389..78298ca434a1f9 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -948,10 +948,14 @@ def temp_dir(path=None, quiet=False): warnings.warn(f'tests may fail, unable to create ' f'temporary directory {path!r}: {exc}', RuntimeWarning, stacklevel=3) + if dir_created: + pid = os.getpid() try: yield path finally: - if dir_created: + # In case the process forks, let only the parent remove the + # directory. The child has a diffent process id. (bpo-30028) + if dir_created and pid == os.getpid(): rmtree(path) @contextlib.contextmanager diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index e06f7b8e9952b8..36d5f849e1ad83 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -9,9 +9,11 @@ import subprocess import sys import tempfile +import textwrap import time import unittest from test import support +from test.support import script_helper TESTFN = support.TESTFN @@ -165,6 +167,33 @@ def test_temp_dir__existing_dir__quiet_true(self): f'temporary directory {path!r}: '), warn) + @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork") + def test_temp_dir__forked_child(self): + """Test that a forked child process does not remove the directory.""" + # See bpo-30028 for details. + # Run the test as an external script, because it uses fork. + script_helper.assert_python_ok("-c", textwrap.dedent(""" + import os + from test import support + with support.temp_cwd() as temp_path: + pid = os.fork() + if pid != 0: + # parent process (child has pid == 0) + + # wait for the child to terminate + (pid, status) = os.waitpid(pid, 0) + if status != 0: + raise AssertionError(f"Child process failed with exit " + f"status indication 0x{status:x}.") + + # Make sure that temp_path is still present. When the child + # process leaves the 'temp_cwd'-context, the __exit__()- + # method of the context must not remove the temporary + # directory. + if not os.path.isdir(temp_path): + raise AssertionError("Child removed temp_path.") + """)) + # Tests for change_cwd() def test_change_cwd(self): diff --git a/Misc/ACKS b/Misc/ACKS index ec7ba956dc08a9..4c0b0e5720e106 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -856,6 +856,7 @@ Pedro Kroger Hannu Krosing Andrej Krpic Ivan Krstić +Anselm Kruis Steven Kryskalla Andrew Kuchling Dave Kuhlman pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy