Skip to content

Commit b76d9bb

Browse files
committed
[lldb] Inherit DuplicateFileAction(HANDLE, HANDLE) handles on windows
This is a follow-up to llvm#126935, which enables passing handles to a child process on windows systems. Unlike on unix-like systems, the handles need to be created with the "inheritable" flag because ...
1 parent 8c7a59f commit b76d9bb

File tree

2 files changed

+60
-18
lines changed

2 files changed

+60
-18
lines changed

lldb/source/Host/windows/ProcessLauncherWindows.cpp

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "lldb/Host/HostProcess.h"
1111
#include "lldb/Host/ProcessLaunchInfo.h"
1212

13+
#include "llvm/ADT/ScopeExit.h"
1314
#include "llvm/ADT/SmallVector.h"
1415
#include "llvm/Support/ConvertUTF.h"
1516
#include "llvm/Support/Program.h"
@@ -65,14 +66,23 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
6566

6667
std::string executable;
6768
std::vector<char> environment;
68-
STARTUPINFO startupinfo = {};
69+
STARTUPINFOEX startupinfoex = {};
70+
STARTUPINFO &startupinfo = startupinfoex.StartupInfo;
6971
PROCESS_INFORMATION pi = {};
7072

7173
HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
7274
HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
7375
HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO);
74-
75-
startupinfo.cb = sizeof(startupinfo);
76+
auto close_handles = llvm::make_scope_exit([&] {
77+
if (stdin_handle)
78+
::CloseHandle(stdin_handle);
79+
if (stdout_handle)
80+
::CloseHandle(stdout_handle);
81+
if (stderr_handle)
82+
::CloseHandle(stderr_handle);
83+
});
84+
85+
startupinfo.cb = sizeof(startupinfoex);
7686
startupinfo.dwFlags |= STARTF_USESTDHANDLES;
7787
startupinfo.hStdError =
7888
stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
@@ -81,6 +91,41 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
8191
startupinfo.hStdOutput =
8292
stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
8393

94+
size_t attributelist_size = 0;
95+
InitializeProcThreadAttributeList(/*lpAttributeList=*/nullptr,
96+
/*dwAttributeCount=*/1, /*dwFlags=*/0,
97+
&attributelist_size);
98+
99+
startupinfoex.lpAttributeList =
100+
static_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(malloc(attributelist_size));
101+
auto free_attributelist =
102+
llvm::make_scope_exit([&] { free(startupinfoex.lpAttributeList); });
103+
if (!InitializeProcThreadAttributeList(startupinfoex.lpAttributeList,
104+
/*dwAttributeCount=*/1, /*dwFlags=*/0,
105+
&attributelist_size)) {
106+
error = Status(::GetLastError(), eErrorTypeWin32);
107+
return HostProcess();
108+
}
109+
auto delete_attributelist = llvm::make_scope_exit(
110+
[&] { DeleteProcThreadAttributeList(startupinfoex.lpAttributeList); });
111+
std::vector<HANDLE> inherited_handles;
112+
for (size_t i = 0; i < launch_info.GetNumFileActions(); ++i) {
113+
const FileAction *act = launch_info.GetFileActionAtIndex(i);
114+
if (act->GetAction() == FileAction::eFileActionDuplicate &&
115+
act->GetFD() == act->GetActionArgument())
116+
inherited_handles.push_back(reinterpret_cast<HANDLE>(act->GetFD()));
117+
}
118+
if (!inherited_handles.empty()) {
119+
if (!UpdateProcThreadAttribute(
120+
startupinfoex.lpAttributeList, /*dwFlags=*/0,
121+
PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
122+
inherited_handles.size() * sizeof(HANDLE),
123+
/*lpPreviousValue=*/nullptr, /*lpReturnSize=*/nullptr)) {
124+
error = Status(::GetLastError(), eErrorTypeWin32);
125+
return HostProcess();
126+
}
127+
}
128+
84129
const char *hide_console_var =
85130
getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
86131
if (hide_console_var &&
@@ -89,7 +134,8 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
89134
startupinfo.wShowWindow = SW_HIDE;
90135
}
91136

92-
DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
137+
DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT |
138+
EXTENDED_STARTUPINFO_PRESENT;
93139
if (launch_info.GetFlags().Test(eLaunchFlagDebug))
94140
flags |= DEBUG_ONLY_THIS_PROCESS;
95141

@@ -116,7 +162,7 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
116162
BOOL result = ::CreateProcessW(
117163
wexecutable.c_str(), pwcommandLine, NULL, NULL, TRUE, flags, env_block,
118164
wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
119-
&startupinfo, &pi);
165+
reinterpret_cast<STARTUPINFO *>(&startupinfoex), &pi);
120166

121167
if (!result) {
122168
// Call GetLastError before we make any other system calls.
@@ -131,13 +177,6 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
131177
::CloseHandle(pi.hThread);
132178
}
133179

134-
if (stdin_handle)
135-
::CloseHandle(stdin_handle);
136-
if (stdout_handle)
137-
::CloseHandle(stdout_handle);
138-
if (stderr_handle)
139-
::CloseHandle(stderr_handle);
140-
141180
if (!result)
142181
return HostProcess();
143182

lldb/unittests/Host/HostTest.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,31 +90,35 @@ TEST(Host, LaunchProcessSetsArgv0) {
9090
ASSERT_THAT(exit_status.get_future().get(), 0);
9191
}
9292

93-
#ifdef LLVM_ON_UNIX
9493
TEST(Host, LaunchProcessDuplicatesHandle) {
9594
static constexpr llvm::StringLiteral test_msg("Hello subprocess!");
9695

9796
SubsystemRAII<FileSystem> subsystems;
9897

9998
if (test_arg) {
100-
Pipe pipe(LLDB_INVALID_PIPE, test_arg);
99+
Pipe pipe(LLDB_INVALID_PIPE,
100+
reinterpret_cast<lldb::pipe_t>(test_arg.getValue()));
101101
llvm::Expected<size_t> bytes_written =
102102
pipe.Write(test_msg.data(), test_msg.size());
103103
if (bytes_written && *bytes_written == test_msg.size())
104104
exit(0);
105105
exit(1);
106106
}
107107
Pipe pipe;
108-
ASSERT_THAT_ERROR(pipe.CreateNew(/*child_process_inherit=*/false).takeError(),
108+
ASSERT_THAT_ERROR(pipe.CreateNew(/*child_process_inherit=*/true).takeError(),
109109
llvm::Succeeded());
110110
ProcessLaunchInfo info;
111111
info.SetExecutableFile(FileSpec(TestMainArgv0),
112112
/*add_exe_file_as_first_arg=*/true);
113113
info.GetArguments().AppendArgument(
114114
"--gtest_filter=Host.LaunchProcessDuplicatesHandle");
115115
info.GetArguments().AppendArgument(
116-
("--test-arg=" + llvm::Twine::utohexstr(pipe.GetWritePipe())).str());
117-
info.AppendDuplicateFileAction(pipe.GetWritePipe(), pipe.GetWritePipe());
116+
("--test-arg=" +
117+
llvm::Twine(reinterpret_cast<uint64_t>(pipe.GetWritePipe())))
118+
.str());
119+
info.AppendDuplicateFileAction(
120+
reinterpret_cast<uint64_t>(pipe.GetWritePipe()),
121+
reinterpret_cast<uint64_t>(pipe.GetWritePipe()));
118122
info.SetMonitorProcessCallback(&ProcessLaunchInfo::NoOpMonitorCallback);
119123
ASSERT_THAT_ERROR(Host::LaunchProcess(info).takeError(), llvm::Succeeded());
120124
pipe.CloseWriteFileDescriptor();
@@ -125,4 +129,3 @@ TEST(Host, LaunchProcessDuplicatesHandle) {
125129
ASSERT_THAT_EXPECTED(bytes_read, llvm::Succeeded());
126130
ASSERT_EQ(llvm::StringRef(msg, *bytes_read), test_msg);
127131
}
128-
#endif

0 commit comments

Comments
 (0)