[Lldb-commits] [lldb] 7a3edbf - [lldb][Windows] Enable the multithreaded and multiple-debuggers API tests (#224305)

via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 23 03:53:30 PDT 2026


Author: Charles Zablit
Date: 2026-09-23T11:53:23+01:00
New Revision: 7a3edbfbcf4acaaabb80e7e5073692690ef920cd

URL: https://github.com/llvm/llvm-project/commit/7a3edbfbcf4acaaabb80e7e5073692690ef920cd
DIFF: https://github.com/llvm/llvm-project/commit/7a3edbfbcf4acaaabb80e7e5073692690ef920cd.diff

LOG: [lldb][Windows] Enable the multithreaded and multiple-debuggers API tests (#224305)

`api/multithreaded` and `api/multiple-debuggers` build a C++ driver
against the SB API. Both were skipped on Windows with `"clang-cl does
not support throw or catch (llvm.org/pr24538)"`, which is no longer what
stops them. Two things do: the drivers fail to compile because
`common.h` and `multi-process-driver.cpp` include `<unistd.h>`
unconditionally, and once they compile they run on a different CRT than
`liblldb.dll`: the gnu-style clang driver links
[`libcmt`](https://github.com/llvm/llvm-project/blob/main/clang/lib/Driver/ToolChains/MSVC.cpp)
unless `-fms-runtime-lib=` is passed, so the driver gets the static CRT
while `liblldb.dll` gets the DLL one.

Fixes:

- Include `<direct.h>` and `<io.h>` instead of `<unistd.h>` on Windows,
and get the working directory with
[`_getcwd`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getcwd-wgetcwd?view=msvc-170).
- `get_working_dir` returns a `std::string` now.
- `test_stop-hook.cpp` uses `_pipe`/`_fdopen` on Windows, and closes the
pipe streams instead of the descriptors they were opened over, write end
first so the interpreter's I/O thread sees EOF.
- Guard the `<unistd.h>` include in `multi-process-driver.cpp`.
- `buildDriver` passes `-fms-runtime-lib=dll` (`dll_dbg` for a Debug
build) and drops the `libcmt` the driver adds at the link step.

`test_breakpoint_location_callback` stays skipped, for an unrelated
reason: `BreakpointCreateByName` with `eFunctionNameTypeFull` resolves
no location in a PDB build, while `eFunctionNameTypeAuto` resolves one.
Tracked in #224303.

rdar://177435499

Added: 
    

Modified: 
    lldb/packages/Python/lldbsuite/test/lldbtest.py
    lldb/test/API/api/multiple-debuggers/TestMultipleDebuggers.py
    lldb/test/API/api/multiple-debuggers/multi-process-driver.cpp
    lldb/test/API/api/multithreaded/TestMultithreaded.py
    lldb/test/API/api/multithreaded/common.h
    lldb/test/API/api/multithreaded/listener_test.cpp
    lldb/test/API/api/multithreaded/test_breakpoint_callback.cpp
    lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp
    lldb/test/API/api/multithreaded/test_stop-hook.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 6e5f844a726300..b5cb1ffd292b1c 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -1772,18 +1772,20 @@ def buildDriver(self, sources, exe_name, defines=None):
                 % (self.lib_lldb, self.framework_dir, lib_dir),
             }
         elif sys.platform.startswith("win"):
+            crt = "dll_dbg" if configuration.cmake_build_type == "debug" else "dll"
             d = {
                 "CXX_SOURCES": sources,
                 "EXE": exe_name,
-                "CFLAGS_EXTRAS": "%s %s -I%s -I%s %s"
+                "CFLAGS_EXTRAS": "%s %s -fms-runtime-lib=%s -I%s -I%s %s"
                 % (
                     stdflag,
                     stdlibflag,
+                    crt,
                     os.path.join(os.environ["LLDB_SRC"], "include"),
                     os.path.join(configuration.lldb_obj_root, "include"),
                     defines,
                 ),
-                "LD_EXTRAS": "-L%s -lliblldb" % lib_dir,
+                "LD_EXTRAS": "-L%s -lliblldb -Xlinker -nodefaultlib:libcmt" % lib_dir,
             }
         else:
             d = {

diff  --git a/lldb/test/API/api/multiple-debuggers/TestMultipleDebuggers.py b/lldb/test/API/api/multiple-debuggers/TestMultipleDebuggers.py
index 13c2f5d961a78f..c6010e109c12fd 100644
--- a/lldb/test/API/api/multiple-debuggers/TestMultipleDebuggers.py
+++ b/lldb/test/API/api/multiple-debuggers/TestMultipleDebuggers.py
@@ -19,7 +19,6 @@ class TestMultipleSimultaneousDebuggers(TestBase):
     # https://github.com/llvm/llvm-project/issues/101162
     @skipIfLinux
     @skipIfNoSBHeaders
-    @skipIfWindows
     @skipIfHostIncompatibleWithTarget
     def test_multiple_debuggers(self):
         self.driver_exe = self.getBuildArtifact("multi-process-driver")

diff  --git a/lldb/test/API/api/multiple-debuggers/multi-process-driver.cpp b/lldb/test/API/api/multiple-debuggers/multi-process-driver.cpp
index 5847dc709a7711..30af50ba389c45 100644
--- a/lldb/test/API/api/multiple-debuggers/multi-process-driver.cpp
+++ b/lldb/test/API/api/multiple-debuggers/multi-process-driver.cpp
@@ -17,7 +17,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifndef _WIN32
 #include <unistd.h>
+#endif
 
 #include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBBroadcaster.h"

diff  --git a/lldb/test/API/api/multithreaded/TestMultithreaded.py b/lldb/test/API/api/multithreaded/TestMultithreaded.py
index 3a3467936a349c..c306fe9b0af751 100644
--- a/lldb/test/API/api/multithreaded/TestMultithreaded.py
+++ b/lldb/test/API/api/multithreaded/TestMultithreaded.py
@@ -18,16 +18,12 @@ def setUp(self):
         TestBase.setUp(self)
 
     @skipIfRemote
-    # clang-cl does not support throw or catch (llvm.org/pr24538)
-    @skipIfWindows
     @skipIfHostIncompatibleWithTarget
     def test_python_stop_hook(self):
         """Test that you can run a python command in a stop-hook when stdin is File based."""
         self.build_and_test("driver.cpp test_stop-hook.cpp", "test_python_stop_hook")
 
     @skipIfRemote
-    # clang-cl does not support throw or catch (llvm.org/pr24538)
-    @skipIfWindows
     @skipIfHostIncompatibleWithTarget
     def test_breakpoint_callback(self):
         """Test the that SBBreakpoint callback is invoked when a breakpoint is hit."""
@@ -36,8 +32,7 @@ def test_breakpoint_callback(self):
         )
 
     @skipIfRemote
-    # clang-cl does not support throw or catch (llvm.org/pr24538)
-    @skipIfWindows
+    @skipIfWindows  # https://github.com/llvm/llvm-project/issues/224303
     @skipIfHostIncompatibleWithTarget
     def test_breakpoint_location_callback(self):
         """Test the that SBBreakpointLocation callback is invoked when a breakpoint is hit."""
@@ -47,8 +42,6 @@ def test_breakpoint_location_callback(self):
         )
 
     @skipIfRemote
-    # clang-cl does not support throw or catch (llvm.org/pr24538)
-    @skipIfWindows
     @expectedFlakeyFreeBSD
     @skipIfHostIncompatibleWithTarget
     def test_sb_api_listener_event_description(self):
@@ -59,8 +52,6 @@ def test_sb_api_listener_event_description(self):
         )
 
     @skipIfRemote
-    # clang-cl does not support throw or catch (llvm.org/pr24538)
-    @skipIfWindows
     @expectedFlakeyFreeBSD
     @skipIfHostIncompatibleWithTarget
     def test_sb_api_listener_event_process_state(self):
@@ -73,8 +64,6 @@ def test_sb_api_listener_event_process_state(self):
         )
 
     @skipIfRemote
-    # clang-cl does not support throw or catch (llvm.org/pr24538)
-    @skipIfWindows
     @expectedFlakeyFreeBSD
     @skipIf(oslist=["linux"])  # flakey
     @skipIfHostIncompatibleWithTarget
@@ -86,8 +75,6 @@ def test_sb_api_listener_resume(self):
         )
 
     @skipIfRemote
-    # clang-cl does not support throw or catch (llvm.org/pr24538)
-    @skipIfWindows
     @skipIfHostIncompatibleWithTarget
     def test_concurrent_unwind(self):
         """Test that you can run a python command in a stop-hook when stdin is File based."""

diff  --git a/lldb/test/API/api/multithreaded/common.h b/lldb/test/API/api/multithreaded/common.h
index 2ef1cb7c5664dc..0df4b771f95500 100644
--- a/lldb/test/API/api/multithreaded/common.h
+++ b/lldb/test/API/api/multithreaded/common.h
@@ -1,15 +1,21 @@
 #ifndef LLDB_TEST_API_COMMON_H
 #define LLDB_TEST_API_COMMON_H
 
-#include <condition_variable>
 #include <chrono>
+#include <condition_variable>
+#include <cstdlib>
 #include <exception>
 #include <iostream>
 #include <mutex>
-#include <string>
 #include <queue>
+#include <string>
 
+#ifdef _WIN32
+#include <direct.h>
+#include <io.h>
+#else
 #include <unistd.h>
+#endif
 
 /// Simple exception class with a message
 struct Exception : public std::exception
@@ -56,14 +62,24 @@ class multithreaded_queue {
   }
 };
 
-/// Allocates a char buffer with the current working directory
-inline char* get_working_dir() {
+/// Returns the current working directory.
+///
+/// The platform accessors all return a malloc'd buffer, so the result is
+/// copied into a std::string and freed here.
+inline std::string get_working_dir() {
 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) ||       \
     defined(__OpenBSD__)
-    return getwd(0);
+  char *dir = getwd(0);
+#elif defined(_WIN32)
+  char *dir = _getcwd(0, 0);
 #else
-    return get_current_dir_name();
+  char *dir = get_current_dir_name();
 #endif
+  if (!dir)
+    return std::string();
+  std::string result(dir);
+  free(dir);
+  return result;
 }
 
 #endif // LLDB_TEST_API_COMMON_H

diff  --git a/lldb/test/API/api/multithreaded/listener_test.cpp b/lldb/test/API/api/multithreaded/listener_test.cpp
index f4f76c6071fb1c..b030bf57b93e92 100644
--- a/lldb/test/API/api/multithreaded/listener_test.cpp
+++ b/lldb/test/API/api/multithreaded/listener_test.cpp
@@ -43,16 +43,16 @@ void test(SBDebugger &dbg, std::vector<string> args) {
     if (!breakpoint.IsValid())
       throw Exception("invalid breakpoint");
 
-    std::unique_ptr<char> working_dir(get_working_dir());
+    std::string working_dir = get_working_dir();
 
     SBError error;
     SBProcess process = target.Launch(g_listener, 0, 0, 0, 0, 0,
-                                      working_dir.get(), 0, false, error);
+                                      working_dir.c_str(), 0, false, error);
     if (!error.Success())
       throw Exception("Error launching process.");
 
     /* FIXME: the approach below deadlocks
-    SBProcess process = target.LaunchSimple (0, 0, working_dir.get());
+    SBProcess process = target.LaunchSimple (0, 0, working_dir.c_str());
 
     // get debugger listener (which is attached to process by default)
     g_listener = dbg.GetListener();

diff  --git a/lldb/test/API/api/multithreaded/test_breakpoint_callback.cpp b/lldb/test/API/api/multithreaded/test_breakpoint_callback.cpp
index 3b8e909cef434e..5cff1cd2b23b66 100644
--- a/lldb/test/API/api/multithreaded/test_breakpoint_callback.cpp
+++ b/lldb/test/API/api/multithreaded/test_breakpoint_callback.cpp
@@ -42,8 +42,8 @@ void test(SBDebugger &dbg, vector<string> args) {
     throw Exception("invalid breakpoint");
   breakpoint.SetCallback(BPCallback, 0);
 
-  std::unique_ptr<char> working_dir(get_working_dir());
-  SBProcess process = target.LaunchSimple(0, 0, working_dir.get());
+  std::string working_dir = get_working_dir();
+  SBProcess process = target.LaunchSimple(0, 0, working_dir.c_str());
 
   {
     unique_lock<mutex> lock(g_mutex);

diff  --git a/lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp b/lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp
index eea3b9ed65f241..2a5d9c42708972 100644
--- a/lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp
+++ b/lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp
@@ -54,8 +54,8 @@ void test(SBDebugger &dbg, vector<string> args) {
   SBBreakpointLocation breakpoint_location = breakpoint.GetLocationAtIndex(0);
   breakpoint_location.SetCallback(BPCallback, 0);
 
-  std::unique_ptr<char> working_dir(get_working_dir());
-  SBProcess process = target.LaunchSimple(0, 0, working_dir.get());
+  std::string working_dir = get_working_dir();
+  SBProcess process = target.LaunchSimple(0, 0, working_dir.c_str());
 
   {
     unique_lock<mutex> lock(g_mutex);

diff  --git a/lldb/test/API/api/multithreaded/test_stop-hook.cpp b/lldb/test/API/api/multithreaded/test_stop-hook.cpp
index a88892340e6138..9c754d131214d3 100644
--- a/lldb/test/API/api/multithreaded/test_stop-hook.cpp
+++ b/lldb/test/API/api/multithreaded/test_stop-hook.cpp
@@ -4,6 +4,10 @@
 
 #include <cstdlib>
 #include <errno.h>
+#ifdef _WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
 #include <mutex>
 #include <stdio.h>
 #include <string>
@@ -86,31 +90,37 @@ void test(SBDebugger &dbg, std::vector<std::string> args) {
   // Now switch the I/O over to a pipe, which will be handled by the
   // NativeFile class:
   int to_lldb_des[2];
+#ifdef _WIN32
+  int pipe_result = _pipe(to_lldb_des, 4096, _O_TEXT);
+  FILE *fh_lldb_in = _fdopen(to_lldb_des[0], "r");
+  FILE *fh_to_lldb = _fdopen(to_lldb_des[1], "w");
+#else
   int pipe_result = pipe(to_lldb_des);
   FILE *fh_lldb_in = fdopen(to_lldb_des[0], "r");
   FILE *fh_to_lldb = fdopen(to_lldb_des[1], "w");
+#endif
 
   // We need to reset the handle before destroying the debugger
   // or the same deadlock will stall exiting:
   class Cleanup {
   public:
-    Cleanup(SBDebugger dbg, int filedes[2]) : m_dbg(dbg) {
+    Cleanup(SBDebugger dbg, FILE *read_end, FILE *write_end)
+        : m_dbg(dbg), m_read_end(read_end), m_write_end(write_end) {
       m_file = m_dbg.GetInputFileHandle();
-      m_filedes[0] = filedes[0];
-      m_filedes[1] = filedes[1];
     }
     ~Cleanup() {
+      fclose(m_write_end);
       m_dbg.SetInputFileHandle(m_file, false);
-      close(m_filedes[0]);
-      close(m_filedes[1]);
+      fclose(m_read_end);
     }
 
   private:
     FILE *m_file;
     SBDebugger m_dbg;
-    int m_filedes[2];
+    FILE *m_read_end;
+    FILE *m_write_end;
   };
-  Cleanup cleanup(dbg, to_lldb_des);
+  Cleanup cleanup(dbg, fh_lldb_in, fh_to_lldb);
 
   dbg.SetInputFileHandle(fh_lldb_in, false);
 


        


More information about the lldb-commits mailing list