[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