From 9ab96964e78f67859acd66088d7b72e9539712df Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 6 Jan 2022 15:08:40 -0500 Subject: [PATCH] faulthandler: don't dump all threads when running without the GIL It's not safe to access other threads stacks when running without the GIL. --- Lib/test/support/script_helper.py | 2 +- Lib/test/test_capi/test_misc.py | 2 +- Lib/test/test_faulthandler.py | 14 ++++++++++---- Modules/faulthandler.c | 5 +++++ Python/pylifecycle.c | 9 ++++++++- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py index c2b43f4060e..5c66261edd4 100644 --- a/Lib/test/support/script_helper.py +++ b/Lib/test/support/script_helper.py @@ -39,7 +39,7 @@ def interpreter_requires_environment(): global __cached_interp_requires_environment if __cached_interp_requires_environment is None: # If PYTHONHOME is set, assume that we need it - if 'PYTHONHOME' in os.environ: + if 'PYTHONHOME' in os.environ or 'PYTHONGIL' in os.environ: __cached_interp_requires_environment = True return True # cannot run subprocess, assume we don't need it diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 5c966e54b69..b317f7883cd 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -311,7 +311,7 @@ def test_getitem_with_error(self): r'Python runtime state: initialized\n' r'ValueError: bug\n' r'\n' - r'Current thread .* \(most recent call first\):\n' + r'(Current thread|Stack).* \(most recent call first\):\n' r' File .*, line 6 in \n' r'\n' r'Extension modules: _testcapi \(total: 1\)\n') diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 8d106daaf65..f816573d301 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -95,21 +95,25 @@ def check_error(self, code, lineno, fatal_error, *, Raise an error if the output doesn't match the expected format. """ + if sys.flags.nogil: + all_threads = False if all_threads: if know_current_thread: header = 'Current thread 0x[0-9a-f]+' else: header = 'Thread 0x[0-9a-f]+' - else: + elif know_current_thread: header = 'Stack' regex = [f'^{fatal_error}'] if py_fatal_error: regex.append("Python runtime state: initialized") regex.append('') - regex.append(fr'{header} \(most recent call first\):') - if garbage_collecting: + if all_threads or know_current_thread: + regex.append(fr'{header} \(most recent call first\):') + if garbage_collecting and all_threads: regex.append(' Garbage-collecting') - regex.append(fr' File "", line {lineno} in {function}') + if all_threads or know_current_thread: + regex.append(fr' File "", line {lineno} in {function}') regex = '\n'.join(regex) if other_regex: @@ -691,6 +695,8 @@ def check_register(self, filename=False, all_threads=False, Raise an error if the output doesn't match the expected format. """ + if sys.flags.nogil: + all_threads = False signum = signal.SIGUSR1 code = """ import faulthandler diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 5309a3728c5..c06f1d3d705 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -183,6 +183,11 @@ faulthandler_dump_traceback(int fd, int all_threads, reentrant = 1; + if (_PyRuntime.preconfig.disable_gil) { + // It's not safe to dump all threads when running without the GIL. + all_threads = 0; + } + /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and are thus delivered to the thread that caused the fault. Get the Python thread state of the current thread. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8ca94d66811..3809aa62ef5 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2559,7 +2559,14 @@ _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp, PUTS(fd, "\n"); /* display the current Python stack */ - _Py_DumpTracebackThreads(fd, interp, tstate); + if (_PyRuntime.preconfig.disable_gil) { + if (tstate != NULL) { + _Py_DumpTraceback(fd, tstate); + } + } + else { + _Py_DumpTracebackThreads(fd, interp, tstate); + } } /* Print the current exception (if an exception is set) with its traceback,