Author: Charles Zablit
Date: 2026-08-11T14:38:01+02:00
New Revision: 870e6890821e6f95dbc1bde35922b73a97e5d169

URL: 
https://github.com/llvm/llvm-project/commit/870e6890821e6f95dbc1bde35922b73a97e5d169
DIFF: 
https://github.com/llvm/llvm-project/commit/870e6890821e6f95dbc1bde35922b73a97e5d169.diff

LOG: [lldb][Windows] Dump thread stacks before lit's timeout kills a test 
(#213239)

On Windows, when a test hits a timeout, we currently don't get a
stacktrace. dotest solves this on POSIX: it registers a SIGTERM handler,
so a killed test prints its stack. The handler does not run on Windows
however because `faulthandler.register` doesn't exist there, and lit
terminates the process instead of signalling it (no signals on Windows).

This patch adds `faulthandler.dump_traceback_later()` with a default
timeout value of 300s. That's longer than the longest test in CI (~150s)
and does not kill the test. It simply dumps the stacktrace at a point
where the test is very likely stuck.

# Before

```
TIMEOUT: lldb-api :: types/TestFloatTypesExpr.py (2698 of 2698)
******************** TEST 'lldb-api :: types/TestFloatTypesExpr.py' FAILED 
********************
Exit Code: 15
Timeout: Reached timeout of 900 seconds
```

There is no stacktrace.

# After

```
Timeout (0:00:20)!
Thread 0x00012fe8 (most recent call first):
  File ".../types/TestFloatTypesExpr.py", line 22 in test_float_type
  File ".../lldbsuite/test/lldbtest.py", line 2097 in test_method
  File ".../unittest/case.py", line 549 in _callTestMethod
  ...
  File ".../lldbsuite/test/dotest.py", line 1212 in run_suite
```

Added: 
    

Modified: 
    lldb/packages/Python/lldbsuite/test/configuration.py
    lldb/packages/Python/lldbsuite/test/dotest.py
    lldb/packages/Python/lldbsuite/test/dotest_args.py
    lldb/test/API/lldbtest.py

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/configuration.py 
b/lldb/packages/Python/lldbsuite/test/configuration.py
index 7f9616be9a482..af069adf9c69e 100644
--- a/lldb/packages/Python/lldbsuite/test/configuration.py
+++ b/lldb/packages/Python/lldbsuite/test/configuration.py
@@ -169,6 +169,10 @@
 # Typical values include Debug, Release, RelWithDebInfo and MinSizeRel
 cmake_build_type = None
 
+# The timeout (in seconds) lit is using to run this test, if any. 0 means no
+# timeout was configured.
+timeout = 0
+
 
 def shouldSkipBecauseOfCategories(test_categories):
     if use_categories:

diff  --git a/lldb/packages/Python/lldbsuite/test/dotest.py 
b/lldb/packages/Python/lldbsuite/test/dotest.py
index 2bd1d085f6ceb..01863c4eab2b0 100644
--- a/lldb/packages/Python/lldbsuite/test/dotest.py
+++ b/lldb/packages/Python/lldbsuite/test/dotest.py
@@ -449,6 +449,8 @@ def parseOptionsAndInitTestdirs():
         configuration.lldb_platform_available_ports = 
args.lldb_platform_available_ports
     if platform_system == "Darwin" and args.apple_sdk:
         configuration.apple_sdk = args.apple_sdk
+    if args.timeout:
+        configuration.timeout = args.timeout
     if args.test_build_dir:
         configuration.test_build_dir = args.test_build_dir
     if args.lldb_module_cache_dir:
@@ -504,6 +506,17 @@ def registerFaulthandler():
     if getattr(faulthandler, "register", None):
         faulthandler.register(signal.SIGTERM, chain=True)
 
+    if sys.platform != "win32":
+        return
+
+    # Dump every thread's stack shortly before lit's own per-test timeout would
+    # kill the process.
+    if configuration.timeout <= 0:
+        return
+
+    secs = max(1.0, configuration.timeout * 0.9)
+    faulthandler.dump_traceback_later(secs, exit=False)
+
 
 def setupSysPath():
     """

diff  --git a/lldb/packages/Python/lldbsuite/test/dotest_args.py 
b/lldb/packages/Python/lldbsuite/test/dotest_args.py
index 41070edf89022..516559fb6268d 100644
--- a/lldb/packages/Python/lldbsuite/test/dotest_args.py
+++ b/lldb/packages/Python/lldbsuite/test/dotest_args.py
@@ -248,6 +248,14 @@ def create_parser():
         ),
         help="The root build directory for the tests. It will be removed 
before running.",
     )
+    group.add_argument(
+        "--timeout",
+        dest="timeout",
+        metavar="Timeout in seconds",
+        type=float,
+        default=0,
+        help="The timeout lit is using to run this test, if any.",
+    )
     group.add_argument(
         "--lldb-module-cache-dir",
         dest="lldb_module_cache_dir",

diff  --git a/lldb/test/API/lldbtest.py b/lldb/test/API/lldbtest.py
index 62952b67bb64f..571b2157542de 100644
--- a/lldb/test/API/lldbtest.py
+++ b/lldb/test/API/lldbtest.py
@@ -55,6 +55,9 @@ def execute(self, test, litConfig):
         # python exe as the first parameter of the command.
         cmd = [executable] + self.dotest_cmd + [testPath, "-p", testFile]
 
+        if test.config.maxIndividualTestTime > 0:
+            cmd += ["--timeout", str(test.config.maxIndividualTestTime)]
+
         launcher = getattr(test.config, "lldb_launcher", None)
         if launcher:
             cmd = [launcher] + cmd


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to