diff options
-rw-r--r-- | Lib/test/test_atexit.py | 16 | ||||
-rw-r--r-- | Python/pylifecycle.c | 2 |
2 files changed, 18 insertions, 0 deletions
diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py index 1d0b018..aa56388 100644 --- a/Lib/test/test_atexit.py +++ b/Lib/test/test_atexit.py @@ -3,6 +3,7 @@ import unittest import io import atexit from test import support +from test.support import script_helper ### helpers def h1(): @@ -152,6 +153,21 @@ class GeneralTest(unittest.TestCase): atexit._run_exitfuncs() self.assertEqual(l, [5]) + def test_shutdown(self): + # Actually test the shutdown mechanism in a subprocess + code = """if 1: + import atexit + + def f(msg): + print(msg) + + atexit.register(f, "one") + atexit.register(f, "two") + """ + res = script_helper.assert_python_ok("-c", code) + self.assertEqual(res.out.decode().splitlines(), ["two", "one"]) + self.assertFalse(res.err) + @support.cpython_only class SubinterpreterTest(unittest.TestCase): diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index fdb09d9..f284855 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2086,6 +2086,8 @@ _Py_FatalInitError(_PyInitError err) /* For the atexit module. */ void _Py_PyAtExit(void (*func)(void)) { + /* Guard against API misuse (see bpo-17852) */ + assert(_PyRuntime.pyexitfunc == NULL || _PyRuntime.pyexitfunc == func); _PyRuntime.pyexitfunc = func; } |