aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test/test_threading.py
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2022-10-31 13:35:54 -0600
committerGitHub <noreply@github.com>2022-10-31 12:35:54 -0700
commit4702552885811d0af8f0e4545f494336801ad4dd (patch)
treea8d24ed97f3e4561bf79ce6d27bd46cba2ecb303 /Lib/test/test_threading.py
parent3b86538661038ee23d0be80bb7593e2e7856f059 (diff)
downloadcpython-4702552885811d0af8f0e4545f494336801ad4dd.tar.gz
cpython-4702552885811d0af8f0e4545f494336801ad4dd.zip
gh-98610: Adjust the Optional Restrictions on Subinterpreters (GH-98618)
Previously, the optional restrictions on subinterpreters were: disallow fork, subprocess, and threads. By default, we were disallowing all three for "isolated" interpreters. We always allowed all three for the main interpreter and those created through the legacy `Py_NewInterpreter()` API. Those settings were a bit conservative, so here we've adjusted the optional restrictions to: fork, exec, threads, and daemon threads. The default for "isolated" interpreters disables fork, exec, and daemon threads. Regular threads are allowed by default. We continue always allowing everything For the main interpreter and the legacy API. In the code, we add `_PyInterpreterConfig.allow_exec` and `_PyInterpreterConfig.allow_daemon_threads`. We also add `Py_RTFLAGS_DAEMON_THREADS` and `Py_RTFLAGS_EXEC`.
Diffstat (limited to 'Lib/test/test_threading.py')
-rw-r--r--Lib/test/test_threading.py56
1 files changed, 56 insertions, 0 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index c6649962331..13ba5068ae2 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -1305,6 +1305,62 @@ class SubinterpThreadingTests(BaseTestCase):
self.assertIn("Fatal Python error: Py_EndInterpreter: "
"not the last thread", err.decode())
+ def _check_allowed(self, before_start='', *,
+ allowed=True,
+ daemon_allowed=True,
+ daemon=False,
+ ):
+ subinterp_code = textwrap.dedent(f"""
+ import test.support
+ import threading
+ def func():
+ print('this should not have run!')
+ t = threading.Thread(target=func, daemon={daemon})
+ {before_start}
+ t.start()
+ """)
+ script = textwrap.dedent(f"""
+ import test.support
+ test.support.run_in_subinterp_with_config(
+ {subinterp_code!r},
+ allow_fork=True,
+ allow_exec=True,
+ allow_threads={allowed},
+ allow_daemon_threads={daemon_allowed},
+ )
+ """)
+ with test.support.SuppressCrashReport():
+ _, _, err = assert_python_ok("-c", script)
+ return err.decode()
+
+ @cpython_only
+ def test_threads_not_allowed(self):
+ err = self._check_allowed(
+ allowed=False,
+ daemon_allowed=False,
+ daemon=False,
+ )
+ self.assertIn('RuntimeError', err)
+
+ @cpython_only
+ def test_daemon_threads_not_allowed(self):
+ with self.subTest('via Thread()'):
+ err = self._check_allowed(
+ allowed=True,
+ daemon_allowed=False,
+ daemon=True,
+ )
+ self.assertIn('RuntimeError', err)
+
+ with self.subTest('via Thread.daemon setter'):
+ err = self._check_allowed(
+ 't.daemon = True',
+ allowed=True,
+ daemon_allowed=False,
+ daemon=False,
+ )
+ self.assertIn('RuntimeError', err)
+
class ThreadingExceptionTests(BaseTestCase):
# A RuntimeError should be raised if Thread.start() is called