[Lldb-commits] [lldb] [lldb][windows] refactor CreateProcessW setup (PR #168733)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Thu Nov 27 03:53:37 PST 2025
https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/168733
>From 71c4fd1953dfa65a215ce347bee3c5d51db41e11 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 19 Nov 2025 16:17:31 +0000
Subject: [PATCH 1/3] [lldb][windows] refactor CreateProcessW setup
---
.../Host/windows/ProcessLauncherWindows.h | 31 ++++++-
.../Host/windows/ProcessLauncherWindows.cpp | 82 ++++++++++---------
2 files changed, 73 insertions(+), 40 deletions(-)
diff --git a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
index 81aea5b2022a5..153086eb9b17c 100644
--- a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
+++ b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
@@ -11,6 +11,9 @@
#include "lldb/Host/ProcessLauncher.h"
#include "lldb/Host/windows/windows.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Environment.h"
+#include "llvm/Support/ErrorOr.h"
namespace lldb_private {
@@ -23,7 +26,33 @@ class ProcessLauncherWindows : public ProcessLauncher {
protected:
HANDLE GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd);
+
+ /// Create a UTF-16 environment block to use with CreateProcessW.
+ ///
+ /// The buffer is a sequence of null-terminated UTF-16 strings, followed by an
+ /// extra L'\0' (two bytes of 0). An empty environment must have one
+ /// empty string, followed by an extra L'\0'.
+ ///
+ /// The keys are sorted to comply with the CreateProcess' calling convention.
+ ///
+ /// Ensure that the resulting buffer is used in conjunction with
+ /// CreateProcessW and be sure that dwCreationFlags includes
+ /// CREATE_UNICODE_ENVIRONMENT.
+ ///
+ /// \param env The Environment object to convert.
+ /// \returns The sorted sequence of environment variables and their values,
+ /// separated by null terminators.
+ static std::vector<wchar_t> CreateEnvironmentBufferW(const Environment &env);
+
+ /// Flattens an Args object into a Windows command-line wide string.
+ ///
+ /// Returns an empty string if args is empty.
+ ///
+ /// \param args The Args object to flatten.
+ /// \returns A wide string containing the flattened command line.
+ static llvm::ErrorOr<std::wstring>
+ GetFlattenedWindowsCommandStringW(Args args);
};
}
-#endif
+#endif
\ No newline at end of file
diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
index f5adadaf061bf..42de009b173e5 100644
--- a/lldb/source/Host/windows/ProcessLauncherWindows.cpp
+++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
@@ -21,42 +21,41 @@
using namespace lldb;
using namespace lldb_private;
-static void CreateEnvironmentBuffer(const Environment &env,
- std::vector<char> &buffer) {
- // The buffer is a list of null-terminated UTF-16 strings, followed by an
- // extra L'\0' (two bytes of 0). An empty environment must have one
- // empty string, followed by an extra L'\0'.
+std::vector<wchar_t>
+ProcessLauncherWindows::CreateEnvironmentBufferW(const Environment &env) {
+ std::vector<std::wstring> env_entries;
for (const auto &KV : env) {
- std::wstring warg;
- if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) {
- buffer.insert(
- buffer.end(), reinterpret_cast<const char *>(warg.c_str()),
- reinterpret_cast<const char *>(warg.c_str() + warg.size() + 1));
+ std::wstring wentry;
+ if (llvm::ConvertUTF8toWide(Environment::compose(KV), wentry)) {
+ env_entries.push_back(std::move(wentry));
}
}
- // One null wchar_t (to end the block) is two null bytes
- buffer.push_back(0);
- buffer.push_back(0);
- // Insert extra two bytes, just in case the environment was empty.
- buffer.push_back(0);
- buffer.push_back(0);
+ std::sort(env_entries.begin(), env_entries.end(),
+ [](const std::wstring &a, const std::wstring &b) {
+ return _wcsicmp(a.c_str(), b.c_str()) < 0;
+ });
+
+ std::vector<wchar_t> buffer;
+ buffer.clear();
+ for (const auto &env_entry : env_entries) {
+ buffer.insert(buffer.end(), env_entry.begin(), env_entry.end());
+ buffer.push_back(L'\0');
+ }
+ buffer.push_back(L'\0');
+
+ return buffer;
}
-static bool GetFlattenedWindowsCommandString(Args args, std::wstring &command) {
+llvm::ErrorOr<std::wstring>
+ProcessLauncherWindows::GetFlattenedWindowsCommandStringW(Args args) {
if (args.empty())
- return false;
+ return L"";
std::vector<llvm::StringRef> args_ref;
for (auto &entry : args.entries())
args_ref.push_back(entry.ref());
- llvm::ErrorOr<std::wstring> result =
- llvm::sys::flattenWindowsCommandLine(args_ref);
- if (result.getError())
- return false;
-
- command = *result;
- return true;
+ return llvm::sys::flattenWindowsCommandLine(args_ref);
}
HostProcess
@@ -66,8 +65,8 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
std::string executable;
std::vector<char> environment;
- STARTUPINFOEX startupinfoex = {};
- STARTUPINFO &startupinfo = startupinfoex.StartupInfo;
+ STARTUPINFOEXW startupinfoex = {};
+ STARTUPINFOW &startupinfo = startupinfoex.StartupInfo;
PROCESS_INFORMATION pi = {};
HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
@@ -149,28 +148,33 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO))
flags &= ~CREATE_NEW_CONSOLE;
- LPVOID env_block = nullptr;
- ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment);
- env_block = environment.data();
-
- executable = launch_info.GetExecutableFile().GetPath();
- std::wstring wcommandLine;
- GetFlattenedWindowsCommandString(launch_info.GetArguments(), wcommandLine);
+ std::vector<wchar_t> environment =
+ CreateEnvironmentBufferW(launch_info.GetEnvironment());
+ LPVOID env_block = environment.empty() ? nullptr : environment.data();
- std::wstring wexecutable, wworkingDirectory;
- llvm::ConvertUTF8toWide(executable, wexecutable);
- llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetPath(),
- wworkingDirectory);
+ auto wcommandLineOrErr =
+ GetFlattenedWindowsCommandStringW(launch_info.GetArguments());
+ if (!wcommandLineOrErr) {
+ error = Status(wcommandLineOrErr.getError());
+ return HostProcess();
+ }
+ std::wstring wcommandLine = *wcommandLineOrErr;
// If the command line is empty, it's best to pass a null pointer to tell
// CreateProcessW to use the executable name as the command line. If the
// command line is not empty, its contents may be modified by CreateProcessW.
WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0];
+ std::wstring wexecutable, wworkingDirectory;
+ llvm::ConvertUTF8toWide(launch_info.GetExecutableFile().GetPath(),
+ wexecutable);
+ llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetPath(),
+ wworkingDirectory);
+
BOOL result = ::CreateProcessW(
wexecutable.c_str(), pwcommandLine, NULL, NULL,
/*bInheritHandles=*/!inherited_handles.empty(), flags, env_block,
wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
- reinterpret_cast<STARTUPINFO *>(&startupinfoex), &pi);
+ reinterpret_cast<STARTUPINFOW *>(&startupinfoex), &pi);
if (!result) {
// Call GetLastError before we make any other system calls.
>From 987ae27154aac1fdbb2de4e3429036803853b169 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 26 Nov 2025 17:10:39 +0000
Subject: [PATCH 2/3] address comments
---
lldb/include/lldb/Host/windows/ProcessLauncherWindows.h | 2 +-
lldb/source/Host/windows/ProcessLauncherWindows.cpp | 4 +---
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
index 153086eb9b17c..a04077a5e1d03 100644
--- a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
+++ b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
@@ -55,4 +55,4 @@ class ProcessLauncherWindows : public ProcessLauncher {
};
}
-#endif
\ No newline at end of file
+#endif
diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
index 42de009b173e5..c6518a811a2c6 100644
--- a/lldb/source/Host/windows/ProcessLauncherWindows.cpp
+++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
@@ -26,9 +26,8 @@ ProcessLauncherWindows::CreateEnvironmentBufferW(const Environment &env) {
std::vector<std::wstring> env_entries;
for (const auto &KV : env) {
std::wstring wentry;
- if (llvm::ConvertUTF8toWide(Environment::compose(KV), wentry)) {
+ if (llvm::ConvertUTF8toWide(Environment::compose(KV), wentry))
env_entries.push_back(std::move(wentry));
- }
}
std::sort(env_entries.begin(), env_entries.end(),
[](const std::wstring &a, const std::wstring &b) {
@@ -36,7 +35,6 @@ ProcessLauncherWindows::CreateEnvironmentBufferW(const Environment &env) {
});
std::vector<wchar_t> buffer;
- buffer.clear();
for (const auto &env_entry : env_entries) {
buffer.insert(buffer.end(), env_entry.begin(), env_entry.end());
buffer.push_back(L'\0');
>From a3029fc8046b2af9ad65ec7052dcf7a8fdead9eb Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Thu, 27 Nov 2025 11:52:11 +0000
Subject: [PATCH 3/3] reverse moving the methods into the class
---
.../Host/windows/ProcessLauncherWindows.h | 29 -------------------
.../Host/windows/ProcessLauncherWindows.cpp | 29 +++++++++++++++----
2 files changed, 24 insertions(+), 34 deletions(-)
diff --git a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
index a04077a5e1d03..81aea5b2022a5 100644
--- a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
+++ b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
@@ -11,9 +11,6 @@
#include "lldb/Host/ProcessLauncher.h"
#include "lldb/Host/windows/windows.h"
-#include "lldb/Utility/Args.h"
-#include "lldb/Utility/Environment.h"
-#include "llvm/Support/ErrorOr.h"
namespace lldb_private {
@@ -26,32 +23,6 @@ class ProcessLauncherWindows : public ProcessLauncher {
protected:
HANDLE GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd);
-
- /// Create a UTF-16 environment block to use with CreateProcessW.
- ///
- /// The buffer is a sequence of null-terminated UTF-16 strings, followed by an
- /// extra L'\0' (two bytes of 0). An empty environment must have one
- /// empty string, followed by an extra L'\0'.
- ///
- /// The keys are sorted to comply with the CreateProcess' calling convention.
- ///
- /// Ensure that the resulting buffer is used in conjunction with
- /// CreateProcessW and be sure that dwCreationFlags includes
- /// CREATE_UNICODE_ENVIRONMENT.
- ///
- /// \param env The Environment object to convert.
- /// \returns The sorted sequence of environment variables and their values,
- /// separated by null terminators.
- static std::vector<wchar_t> CreateEnvironmentBufferW(const Environment &env);
-
- /// Flattens an Args object into a Windows command-line wide string.
- ///
- /// Returns an empty string if args is empty.
- ///
- /// \param args The Args object to flatten.
- /// \returns A wide string containing the flattened command line.
- static llvm::ErrorOr<std::wstring>
- GetFlattenedWindowsCommandStringW(Args args);
};
}
diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
index c6518a811a2c6..d158638221bf5 100644
--- a/lldb/source/Host/windows/ProcessLauncherWindows.cpp
+++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
@@ -21,8 +21,22 @@
using namespace lldb;
using namespace lldb_private;
-std::vector<wchar_t>
-ProcessLauncherWindows::CreateEnvironmentBufferW(const Environment &env) {
+/// Create a UTF-16 environment block to use with CreateProcessW.
+///
+/// The buffer is a sequence of null-terminated UTF-16 strings, followed by an
+/// extra L'\0' (two bytes of 0). An empty environment must have one
+/// empty string, followed by an extra L'\0'.
+///
+/// The keys are sorted to comply with the CreateProcess' calling convention.
+///
+/// Ensure that the resulting buffer is used in conjunction with
+/// CreateProcessW and be sure that dwCreationFlags includes
+/// CREATE_UNICODE_ENVIRONMENT.
+///
+/// \param env The Environment object to convert.
+/// \returns The sorted sequence of environment variables and their values,
+/// separated by null terminators.
+static std::vector<wchar_t> CreateEnvironmentBufferW(const Environment &env) {
std::vector<std::wstring> env_entries;
for (const auto &KV : env) {
std::wstring wentry;
@@ -44,8 +58,14 @@ ProcessLauncherWindows::CreateEnvironmentBufferW(const Environment &env) {
return buffer;
}
-llvm::ErrorOr<std::wstring>
-ProcessLauncherWindows::GetFlattenedWindowsCommandStringW(Args args) {
+/// Flattens an Args object into a Windows command-line wide string.
+///
+/// Returns an empty string if args is empty.
+///
+/// \param args The Args object to flatten.
+/// \returns A wide string containing the flattened command line.
+static llvm::ErrorOr<std::wstring>
+GetFlattenedWindowsCommandStringW(Args args) {
if (args.empty())
return L"";
@@ -62,7 +82,6 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
error.Clear();
std::string executable;
- std::vector<char> environment;
STARTUPINFOEXW startupinfoex = {};
STARTUPINFOW &startupinfo = startupinfoex.StartupInfo;
PROCESS_INFORMATION pi = {};
More information about the lldb-commits
mailing list