summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2024-01-25 17:15:33 +0100
committerHelmut Grohne <helmut@subdivi.de>2024-01-25 17:19:24 +0100
commit75c3b33550624fecb551b16f95ea65bf3323934f (patch)
tree689d86932452de58c5de06dd161de7ce1ae14b0d
parentf01c7690de8e9ea1c287d336d32b530c441c458f (diff)
downloadpython-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__.py2
-rw-r--r--tests/test_simple.py22
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