]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-151278: Fix test_faulthandler on UBSan (GH-151279) (#151281)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 10 Jun 2026 20:07:07 +0000 (22:07 +0200)
committerGitHub <noreply@github.com>
Wed, 10 Jun 2026 20:07:07 +0000 (20:07 +0000)
gh-151278: Fix test_faulthandler on UBSan (GH-151279)

* Py_FatalError() no longer calls _PyFaulthandler_Fini() if it
  doesn't hold the GIL.
* Skip test_faulthandler tests raising signals if run with UBSan.
* Enable test_faulthandler in GitHub Action "Reusable Sanitizer".
(cherry picked from commit e60c42dc3f5a8dd9b10bc9a8a028ef2765469650)

Co-authored-by: Victor Stinner <vstinner@python.org>
.github/workflows/reusable-san.yml
Lib/test/test_faulthandler.py
Python/pylifecycle.c

index d1e9cb9636698b9cc4f344e936e6d5aeaec8221a..6127c7e1c05369031c1fbfb4a00514a059424eb3 100644 (file)
@@ -82,13 +82,13 @@ jobs:
       run: make -j4
     - name: Display build info
       run: make pythoninfo
-    # test_{capi,faulthandler} are skipped under UBSan because
+    # test_capi is skipped under UBSan because
     # they raise signals that UBSan with halt_on_error=1 intercepts.
     - name: Tests
       run: >-
         ./python -m test
         ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }}
-        ${{ inputs.sanitizer == 'UBSan' && '-x test_capi -x test_faulthandler' || '' }}
+        ${{ inputs.sanitizer == 'UBSan' && '-x test_capi' || '' }}
         -j4 -W
     - name: Parallel tests
       if: >-
index 11df59f2346f3166d5bb63466ef0ae9084c54d4a..5a493a4fd9568029706143ea7c5cc152b31f9368 100644 (file)
@@ -33,6 +33,11 @@ CURRENT_THREAD_ID = fr'Current thread 0x[0-9a-f]+{THREAD_NAME}'
 CURRENT_THREAD_HEADER = fr'{CURRENT_THREAD_ID} \(most recent call first\):'
 
 
+def skip_if_sanitizer_signal(signame):
+    return support.skip_if_sanitizer(f"TSAN/UBSan itercepts {signame}",
+                                     thread=True, ub=True)
+
+
 def expected_traceback(lineno1, lineno2, header, min_count=1):
     regex = header
     regex += '  File "<string>", line %s in func\n' % lineno1
@@ -224,7 +229,7 @@ class FaultHandlerTests(unittest.TestCase):
             func='faulthandler_fatal_error_thread',
             py_fatal_error=True)
 
-    @support.skip_if_sanitizer("TSAN itercepts SIGABRT", thread=True)
+    @skip_if_sanitizer_signal("SIGABRT")
     def test_sigabrt(self):
         self.check_fatal_error("""
             import faulthandler
@@ -236,7 +241,7 @@ class FaultHandlerTests(unittest.TestCase):
 
     @unittest.skipIf(sys.platform == 'win32',
                      "SIGFPE cannot be caught on Windows")
-    @support.skip_if_sanitizer("TSAN itercepts SIGFPE", thread=True)
+    @skip_if_sanitizer_signal("SIGFPE")
     def test_sigfpe(self):
         self.check_fatal_error("""
             import faulthandler
@@ -248,7 +253,7 @@ class FaultHandlerTests(unittest.TestCase):
 
     @unittest.skipIf(_testcapi is None, 'need _testcapi')
     @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
-    @support.skip_if_sanitizer("TSAN itercepts SIGBUS", thread=True)
+    @skip_if_sanitizer_signal("SIGBUS")
     @skip_segfault_on_android
     def test_sigbus(self):
         self.check_fatal_error("""
@@ -263,7 +268,7 @@ class FaultHandlerTests(unittest.TestCase):
 
     @unittest.skipIf(_testcapi is None, 'need _testcapi')
     @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
-    @support.skip_if_sanitizer("TSAN itercepts SIGILL", thread=True)
+    @skip_if_sanitizer_signal("SIGILL")
     @skip_segfault_on_android
     def test_sigill(self):
         self.check_fatal_error("""
index 0bdc7ddd92dc823fbd941dfb94e42fce061b727d..311332434d69a4455b7bd3e777b6bcf5264bf9f5 100644 (file)
@@ -3724,7 +3724,9 @@ fatal_error(int fd, int header, const char *prefix, const char *msg,
        This function already did its best to display a traceback.
        Disable faulthandler to prevent writing a second traceback
        on abort(). */
-    _PyFaulthandler_Fini();
+    if (has_tstate_and_gil) {
+        _PyFaulthandler_Fini();
+    }
 
     /* Check if the current Python thread hold the GIL */
     if (has_tstate_and_gil) {