diff options
author | Helmut Grohne <helmut@subdivi.de> | 2024-01-25 17:15:33 +0100 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2024-01-25 17:19:24 +0100 |
commit | 75c3b33550624fecb551b16f95ea65bf3323934f (patch) | |
tree | 689d86932452de58c5de06dd161de7ce1ae14b0d | |
parent | f01c7690de8e9ea1c287d336d32b530c441c458f (diff) | |
download | python-linuxnamespaces-75c3b33550624fecb551b16f95ea65bf3323934f.tar.gz |
linuxnamespaces.run_in_fork: use os._exit instead of sys.exit
When using sys.exit, we actually raise a SystemExit exception and as a
consequence exit all context managers. If a particular context manager
pertains only the process at hand, we don't really care, because our
process is supposed to vanish. If a context manager changes external
state such as tempfile.NamedTemporaryFile, this is very bad and
unexpected. We need to ensure that such cleanup is not performed.
This also simplifies the test suite that had to emulate this behaviour
already as pytest uses a context manager.
-rw-r--r-- | linuxnamespaces/__init__.py | 2 | ||||
-rw-r--r-- | tests/test_simple.py | 22 |
2 files changed, 4 insertions, 20 deletions
diff --git a/linuxnamespaces/__init__.py b/linuxnamespaces/__init__.py index f44220a..c060e01 100644 --- a/linuxnamespaces/__init__.py +++ b/linuxnamespaces/__init__.py @@ -210,7 +210,7 @@ class run_in_fork: self.efd.read() self.efd.close() function() - sys.exit(0) + os._exit(0) def start(self) -> None: """Start the decorated function. It can only be started once.""" diff --git a/tests/test_simple.py b/tests/test_simple.py index 8469bb4..cb654aa 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -12,22 +12,6 @@ import pytest import linuxnamespaces -def allow_fork_exit(function): - @functools.wraps(function) - def wrapped(*args, **kwargs): - mainpid = os.getpid() - try: - return function(*args, **kwargs) - except SystemExit as sysexit: - if sysexit.code or os.getpid() == mainpid: - raise - - # We're supposed to successfully exit from a child process. If we - # were to return or raise here, pytest would record success or - # failure. Instead we hide this process from pytest. - os._exit(0) - return pytest.mark.forked(wrapped) - class IDAllocationTest(unittest.TestCase): def test_idalloc(self) -> None: alloc = linuxnamespaces.IDAllocation() @@ -58,7 +42,7 @@ class UnshareTest(unittest.TestCase): # UID 1 is not mapped. self.assertRaises(OSError, os.setuid, 1) - @allow_fork_exit + @pytest.mark.forked def test_mount_proc(self) -> None: idmap = linuxnamespaces.IDMapping(0, os.getuid(), 1) linuxnamespaces.unshare( @@ -108,7 +92,7 @@ class UnshareIdmapTest(unittest.TestCase): except ValueError: self.skipTest("insufficient /etc/sub?id allocation") - @allow_fork_exit + @pytest.mark.forked def test_unshare_user_idmap(self) -> None: overflowuid = int(pathlib.Path("/proc/sys/fs/overflowuid").read_text()) uidmap = linuxnamespaces.IDMapping( @@ -131,7 +115,7 @@ class UnshareIdmapTest(unittest.TestCase): os.setuid(1) self.assertEqual(os.getuid(), 1) - @allow_fork_exit + @pytest.mark.forked def test_populate_dev(self) -> None: uidmap = linuxnamespaces.IDMapping( 0, self.uidalloc.allocate(65536), 65536 |