Skip to content

Commit 9bfea88

Browse files
charles-zablitcompnerd
authored andcommitted
[NFC][lldb][windows] refactor the creation of inherited handles (llvm#170301)
Co-authored-by: Saleem Abdulrasool <[email protected]>
1 parent 817ab49 commit 9bfea88

File tree

4 files changed

+111
-50
lines changed

4 files changed

+111
-50
lines changed

lldb/include/lldb/Host/windows/ProcessLauncherWindows.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "lldb/Host/ProcessLauncher.h"
1313
#include "lldb/Host/windows/windows.h"
14+
#include "llvm/Support/ErrorOr.h"
1415

1516
namespace lldb_private {
1617

@@ -23,6 +24,36 @@ class ProcessLauncherWindows : public ProcessLauncher {
2324

2425
protected:
2526
HANDLE GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd);
27+
28+
/// Get the list of Windows handles that should be inherited by the child
29+
/// process and update `STARTUPINFOEXW` with the handle list.
30+
///
31+
/// If no handles need to be inherited, an empty vector is returned.
32+
///
33+
/// Otherwise, the function populates the
34+
/// `PROC_THREAD_ATTRIBUTE_HANDLE_LIST` attribute in `startupinfoex` with the
35+
/// collected handles using `UpdateProcThreadAttribute`. On success, the
36+
/// vector of inherited handles is returned.
37+
///
38+
/// \param launch_info
39+
/// The process launch configuration.
40+
///
41+
/// \param startupinfoex
42+
/// The extended STARTUPINFO structure for the process being created.
43+
///
44+
/// \param stdout_handle
45+
/// \param stderr_handle
46+
/// \param stdin_handle
47+
/// Optional explicit standard stream handles to use for the child process.
48+
///
49+
/// \returns
50+
/// `std::vector<HANDLE>` containing all handles that the child must
51+
/// inherit.
52+
llvm::ErrorOr<std::vector<HANDLE>>
53+
GetInheritedHandles(const ProcessLaunchInfo &launch_info,
54+
STARTUPINFOEXW &startupinfoex,
55+
HANDLE stdout_handle = NULL, HANDLE stderr_handle = NULL,
56+
HANDLE stdin_handle = NULL);
2657
};
2758
}
2859

lldb/source/Host/windows/ProcessLauncherWindows.cpp

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/ADT/SmallVector.h"
1515
#include "llvm/Support/ConvertUTF.h"
1616
#include "llvm/Support/Program.h"
17+
#include "llvm/Support/WindowsError.h"
1718

1819
#include <string>
1920
#include <vector>
@@ -86,10 +87,14 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
8687
error.Clear();
8788

8889
std::string executable;
90+
std::vector<HANDLE> inherited_handles;
8991
STARTUPINFOEXW startupinfoex = {};
9092
STARTUPINFOW &startupinfo = startupinfoex.StartupInfo;
9193
PROCESS_INFORMATION pi = {};
9294

95+
startupinfo.cb = sizeof(startupinfoex);
96+
startupinfo.dwFlags |= STARTF_USESTDHANDLES;
97+
9398
HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
9499
HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
95100
HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO);
@@ -102,22 +107,13 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
102107
::CloseHandle(stderr_handle);
103108
});
104109

105-
startupinfo.cb = sizeof(startupinfoex);
106-
startupinfo.dwFlags |= STARTF_USESTDHANDLES;
107-
startupinfo.hStdError =
108-
stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
109-
startupinfo.hStdInput =
110-
stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE);
111-
startupinfo.hStdOutput =
112-
stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
113-
114-
std::vector<HANDLE> inherited_handles;
115-
if (startupinfo.hStdError)
116-
inherited_handles.push_back(startupinfo.hStdError);
117-
if (startupinfo.hStdInput)
118-
inherited_handles.push_back(startupinfo.hStdInput);
119-
if (startupinfo.hStdOutput)
120-
inherited_handles.push_back(startupinfo.hStdOutput);
110+
auto inherited_handles_or_err = GetInheritedHandles(
111+
launch_info, startupinfoex, stdout_handle, stderr_handle, stdin_handle);
112+
if (!inherited_handles_or_err) {
113+
error = Status(inherited_handles_or_err.getError());
114+
return HostProcess();
115+
}
116+
inherited_handles = *inherited_handles_or_err;
121117

122118
SIZE_T attributelist_size = 0;
123119
InitializeProcThreadAttributeList(/*lpAttributeList=*/nullptr,
@@ -136,22 +132,6 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
136132
}
137133
auto delete_attributelist = llvm::make_scope_exit(
138134
[&] { DeleteProcThreadAttributeList(startupinfoex.lpAttributeList); });
139-
for (size_t i = 0; i < launch_info.GetNumFileActions(); ++i) {
140-
const FileAction *act = launch_info.GetFileActionAtIndex(i);
141-
if (act->GetAction() == FileAction::eFileActionDuplicate &&
142-
act->GetFD() == act->GetActionArgument())
143-
inherited_handles.push_back(reinterpret_cast<HANDLE>(act->GetFD()));
144-
}
145-
if (!inherited_handles.empty()) {
146-
if (!UpdateProcThreadAttribute(
147-
startupinfoex.lpAttributeList, /*dwFlags=*/0,
148-
PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
149-
inherited_handles.size() * sizeof(HANDLE),
150-
/*lpPreviousValue=*/nullptr, /*lpReturnSize=*/nullptr)) {
151-
error = Status(::GetLastError(), eErrorTypeWin32);
152-
return HostProcess();
153-
}
154-
}
155135

156136
const char *hide_console_var =
157137
getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
@@ -215,6 +195,46 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
215195
return HostProcess(pi.hProcess);
216196
}
217197

198+
llvm::ErrorOr<std::vector<HANDLE>> ProcessLauncherWindows::GetInheritedHandles(
199+
const ProcessLaunchInfo &launch_info, STARTUPINFOEXW &startupinfoex,
200+
HANDLE stdout_handle, HANDLE stderr_handle, HANDLE stdin_handle) {
201+
std::vector<HANDLE> inherited_handles;
202+
STARTUPINFOW startupinfo = startupinfoex.StartupInfo;
203+
204+
startupinfo.hStdError =
205+
stderr_handle ? stderr_handle : GetStdHandle(STD_ERROR_HANDLE);
206+
startupinfo.hStdInput =
207+
stdin_handle ? stdin_handle : GetStdHandle(STD_INPUT_HANDLE);
208+
startupinfo.hStdOutput =
209+
stdout_handle ? stdout_handle : GetStdHandle(STD_OUTPUT_HANDLE);
210+
211+
if (startupinfo.hStdError)
212+
inherited_handles.push_back(startupinfo.hStdError);
213+
if (startupinfo.hStdInput)
214+
inherited_handles.push_back(startupinfo.hStdInput);
215+
if (startupinfo.hStdOutput)
216+
inherited_handles.push_back(startupinfo.hStdOutput);
217+
218+
for (size_t i = 0; i < launch_info.GetNumFileActions(); ++i) {
219+
const FileAction *act = launch_info.GetFileActionAtIndex(i);
220+
if (act->GetAction() == FileAction::eFileActionDuplicate &&
221+
act->GetFD() == act->GetActionArgument())
222+
inherited_handles.push_back(reinterpret_cast<HANDLE>(act->GetFD()));
223+
}
224+
225+
if (inherited_handles.empty())
226+
return inherited_handles;
227+
228+
if (!UpdateProcThreadAttribute(
229+
startupinfoex.lpAttributeList, /*dwFlags=*/0,
230+
PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
231+
inherited_handles.size() * sizeof(HANDLE),
232+
/*lpPreviousValue=*/nullptr, /*lpReturnSize=*/nullptr))
233+
return llvm::mapWindowsError(::GetLastError());
234+
235+
return inherited_handles;
236+
}
237+
218238
HANDLE
219239
ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info,
220240
int fd) {

llvm/include/llvm/IR/User.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ class User : public Value {
141141
LLVM_ABI void growHungoffUses(unsigned N, bool IsPhi = false);
142142

143143
protected:
144-
~User() = default; // Use deleteValue() to delete a generic Instruction.
144+
// Use deleteValue() to delete a generic User.
145+
~User();
145146

146147
public:
147148
User(const User &) = delete;

llvm/lib/IR/User.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ bool User::isDroppable() const {
135135

136136
void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
137137
unsigned DescBytes) {
138+
assert(Us > 0 && "Should have at least one operand");
138139
assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
139140

140141
static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");
@@ -189,31 +190,39 @@ void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
189190
// User operator delete Implementation
190191
//===----------------------------------------------------------------------===//
191192

192-
// Repress memory sanitization, due to use-after-destroy by operator
193-
// delete. Bug report 24578 identifies this issue.
194-
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
193+
User::~User() {
195194
// Hung off uses use a single Use* before the User, while other subclasses
196195
// use a Use[] allocated prior to the user.
197-
User *Obj = static_cast<User *>(Usr);
198-
if (Obj->HasHungOffUses) {
199-
assert(!Obj->HasDescriptor && "not supported!");
196+
void *AllocStart = nullptr;
197+
if (HasHungOffUses) {
198+
assert(!HasDescriptor && "not supported!");
200199

201-
Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
200+
Use **HungOffOperandList = reinterpret_cast<Use **>(this) - 1;
202201
// drop the hung off uses.
203-
Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
202+
Use::zap(*HungOffOperandList, *HungOffOperandList + NumUserOperands,
204203
/* Delete */ true);
205-
::operator delete(HungOffOperandList);
206-
} else if (Obj->HasDescriptor) {
207-
Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
208-
Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false);
204+
AllocStart = HungOffOperandList;
205+
} else if (HasDescriptor) {
206+
Use *UseBegin = reinterpret_cast<Use *>(this) - NumUserOperands;
207+
Use::zap(UseBegin, UseBegin + NumUserOperands, /* Delete */ false);
209208

210209
auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
211-
uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
212-
::operator delete(Storage);
210+
AllocStart = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
213211
} else {
214-
Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
215-
Use::zap(Storage, Storage + Obj->NumUserOperands,
212+
Use *Storage = reinterpret_cast<Use *>(this) - NumUserOperands;
213+
assert(NumUserOperands > 0 && "Should have at least one operand");
214+
Use::zap(Storage, Storage + NumUserOperands,
216215
/* Delete */ false);
217-
::operator delete(Storage);
216+
AllocStart = Storage;
218217
}
218+
219+
// Operator delete needs to know where the allocation started. To avoid
220+
// use-after-destroy, we have to store the allocation start outside the User
221+
// object memory. We always have at least one Use* before the User, so we can
222+
// use that to store the allocation start.
223+
((void **)this)[-1] = AllocStart;
224+
}
225+
226+
void User::operator delete(void *Usr) {
227+
::operator delete(((void **)Usr)[-1]);
219228
}

0 commit comments

Comments
 (0)