Skip to content

Commit 44bd663

Browse files
Merge branch 'main' into patch-1
2 parents 3edbcb9 + e6ae246 commit 44bd663

File tree

5 files changed

+160
-95
lines changed

5 files changed

+160
-95
lines changed

lldb/source/Host/windows/ProcessLauncherWindows.cpp

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,42 +21,63 @@
2121
using namespace lldb;
2222
using namespace lldb_private;
2323

24-
static void CreateEnvironmentBuffer(const Environment &env,
25-
std::vector<char> &buffer) {
26-
// The buffer is a list of null-terminated UTF-16 strings, followed by an
27-
// extra L'\0' (two bytes of 0). An empty environment must have one
28-
// empty string, followed by an extra L'\0'.
24+
/// Create a UTF-16 environment block to use with CreateProcessW.
25+
///
26+
/// The buffer is a sequence of null-terminated UTF-16 strings, followed by an
27+
/// extra L'\0' (two bytes of 0). An empty environment must have one
28+
/// empty string, followed by an extra L'\0'.
29+
///
30+
/// The keys are sorted to comply with the CreateProcess API calling convention.
31+
///
32+
/// Ensure that the resulting buffer is used in conjunction with
33+
/// CreateProcessW and be sure that dwCreationFlags includes
34+
/// CREATE_UNICODE_ENVIRONMENT.
35+
///
36+
/// \param env The Environment object to convert.
37+
/// \returns The sorted sequence of environment variables and their values,
38+
/// separated by null terminators. The vector is guaranteed to never be empty.
39+
static std::vector<wchar_t> CreateEnvironmentBufferW(const Environment &env) {
40+
std::vector<std::wstring> env_entries;
2941
for (const auto &KV : env) {
30-
std::wstring warg;
31-
if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) {
32-
buffer.insert(
33-
buffer.end(), reinterpret_cast<const char *>(warg.c_str()),
34-
reinterpret_cast<const char *>(warg.c_str() + warg.size() + 1));
35-
}
42+
std::wstring wentry;
43+
if (llvm::ConvertUTF8toWide(Environment::compose(KV), wentry))
44+
env_entries.push_back(std::move(wentry));
45+
}
46+
std::sort(env_entries.begin(), env_entries.end(),
47+
[](const std::wstring &a, const std::wstring &b) {
48+
return _wcsicmp(a.c_str(), b.c_str()) < 0;
49+
});
50+
51+
std::vector<wchar_t> buffer;
52+
for (const auto &env_entry : env_entries) {
53+
buffer.insert(buffer.end(), env_entry.begin(), env_entry.end());
54+
buffer.push_back(L'\0');
3655
}
37-
// One null wchar_t (to end the block) is two null bytes
38-
buffer.push_back(0);
39-
buffer.push_back(0);
40-
// Insert extra two bytes, just in case the environment was empty.
41-
buffer.push_back(0);
42-
buffer.push_back(0);
56+
57+
if (buffer.empty())
58+
buffer.push_back(L'\0'); // If there are no environment variables, we have
59+
// to ensure there are 4 zero bytes in the buffer.
60+
buffer.push_back(L'\0');
61+
62+
return buffer;
4363
}
4464

45-
static bool GetFlattenedWindowsCommandString(Args args, std::wstring &command) {
65+
/// Flattens an Args object into a Windows command-line wide string.
66+
///
67+
/// Returns an empty string if args is empty.
68+
///
69+
/// \param args The Args object to flatten.
70+
/// \returns A wide string containing the flattened command line.
71+
static llvm::ErrorOr<std::wstring>
72+
GetFlattenedWindowsCommandStringW(Args args) {
4673
if (args.empty())
47-
return false;
74+
return L"";
4875

4976
std::vector<llvm::StringRef> args_ref;
5077
for (auto &entry : args.entries())
5178
args_ref.push_back(entry.ref());
5279

53-
llvm::ErrorOr<std::wstring> result =
54-
llvm::sys::flattenWindowsCommandLine(args_ref);
55-
if (result.getError())
56-
return false;
57-
58-
command = *result;
59-
return true;
80+
return llvm::sys::flattenWindowsCommandLine(args_ref);
6081
}
6182

6283
HostProcess
@@ -65,9 +86,8 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
6586
error.Clear();
6687

6788
std::string executable;
68-
std::vector<char> environment;
69-
STARTUPINFOEX startupinfoex = {};
70-
STARTUPINFO &startupinfo = startupinfoex.StartupInfo;
89+
STARTUPINFOEXW startupinfoex = {};
90+
STARTUPINFOW &startupinfo = startupinfoex.StartupInfo;
7191
PROCESS_INFORMATION pi = {};
7292

7393
HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
@@ -149,28 +169,32 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
149169
if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO))
150170
flags &= ~CREATE_NEW_CONSOLE;
151171

152-
LPVOID env_block = nullptr;
153-
::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment);
154-
env_block = environment.data();
155-
156-
executable = launch_info.GetExecutableFile().GetPath();
157-
std::wstring wcommandLine;
158-
GetFlattenedWindowsCommandString(launch_info.GetArguments(), wcommandLine);
172+
std::vector<wchar_t> environment =
173+
CreateEnvironmentBufferW(launch_info.GetEnvironment());
159174

160-
std::wstring wexecutable, wworkingDirectory;
161-
llvm::ConvertUTF8toWide(executable, wexecutable);
162-
llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetPath(),
163-
wworkingDirectory);
175+
auto wcommandLineOrErr =
176+
GetFlattenedWindowsCommandStringW(launch_info.GetArguments());
177+
if (!wcommandLineOrErr) {
178+
error = Status(wcommandLineOrErr.getError());
179+
return HostProcess();
180+
}
181+
std::wstring wcommandLine = *wcommandLineOrErr;
164182
// If the command line is empty, it's best to pass a null pointer to tell
165183
// CreateProcessW to use the executable name as the command line. If the
166184
// command line is not empty, its contents may be modified by CreateProcessW.
167185
WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0];
168186

187+
std::wstring wexecutable, wworkingDirectory;
188+
llvm::ConvertUTF8toWide(launch_info.GetExecutableFile().GetPath(),
189+
wexecutable);
190+
llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetPath(),
191+
wworkingDirectory);
192+
169193
BOOL result = ::CreateProcessW(
170194
wexecutable.c_str(), pwcommandLine, NULL, NULL,
171-
/*bInheritHandles=*/!inherited_handles.empty(), flags, env_block,
195+
/*bInheritHandles=*/!inherited_handles.empty(), flags, environment.data(),
172196
wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
173-
reinterpret_cast<STARTUPINFO *>(&startupinfoex), &pi);
197+
reinterpret_cast<STARTUPINFOW *>(&startupinfoex), &pi);
174198

175199
if (!result) {
176200
// Call GetLastError before we make any other system calls.

llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ class LLVM_ABI AppleAcceleratorTable : public DWARFAcceleratorTable {
153153
uint64_t getHashBase() const { return getBucketBase() + getNumBuckets() * 4; }
154154

155155
/// Return the offset into the section where the I-th hash is.
156-
uint64_t getIthHashBase(uint32_t I) const { return getHashBase() + I * 4; }
156+
std::optional<uint64_t> getIthHashBase(uint32_t I) const {
157+
if (I < Hdr.HashCount)
158+
return getHashBase() + I * 4;
159+
return std::nullopt;
160+
}
157161

158162
/// Return the offset into the section where the offset list begins.
159163
uint64_t getOffsetBase() const { return getHashBase() + getNumHashes() * 4; }
@@ -164,8 +168,10 @@ class LLVM_ABI AppleAcceleratorTable : public DWARFAcceleratorTable {
164168
}
165169

166170
/// Return the offset into the section where the I-th offset is.
167-
uint64_t getIthOffsetBase(uint32_t I) const {
168-
return getOffsetBase() + I * 4;
171+
std::optional<uint64_t> getIthOffsetBase(uint32_t I) const {
172+
if (I < Hdr.HashCount)
173+
return getOffsetBase() + I * 4;
174+
return std::nullopt;
169175
}
170176

171177
/// Returns the index of the bucket where a hypothetical Hash would be.
@@ -188,14 +194,18 @@ class LLVM_ABI AppleAcceleratorTable : public DWARFAcceleratorTable {
188194

189195
/// Reads the I-th hash in the hash list.
190196
std::optional<uint32_t> readIthHash(uint32_t I) const {
191-
uint64_t Offset = getIthHashBase(I);
192-
return readU32FromAccel(Offset);
197+
std::optional<uint64_t> OptOffset = getIthHashBase(I);
198+
if (OptOffset)
199+
return readU32FromAccel(*OptOffset);
200+
return std::nullopt;
193201
}
194202

195203
/// Reads the I-th offset in the offset list.
196204
std::optional<uint32_t> readIthOffset(uint32_t I) const {
197-
uint64_t Offset = getIthOffsetBase(I);
198-
return readU32FromAccel(Offset);
205+
std::optional<uint64_t> OptOffset = getIthOffsetBase(I);
206+
if (OptOffset)
207+
return readU32FromAccel(*OptOffset);
208+
return std::nullopt;
199209
}
200210

201211
/// Reads a string offset from the accelerator table at Offset, which is
@@ -282,6 +292,7 @@ class LLVM_ABI AppleAcceleratorTable : public DWARFAcceleratorTable {
282292
constexpr static auto EndMarker = std::numeric_limits<uint64_t>::max();
283293

284294
EntryWithName Current;
295+
uint32_t OffsetIdx = 0;
285296
uint64_t Offset = EndMarker;
286297
uint32_t NumEntriesToCome = 0;
287298

@@ -298,7 +309,9 @@ class LLVM_ABI AppleAcceleratorTable : public DWARFAcceleratorTable {
298309
/// Reads the next string pointer and the entry count for that string,
299310
/// populating `NumEntriesToCome`.
300311
/// If not possible (e.g. end of the section), becomes the end iterator.
301-
/// Assumes `Offset` points to a string reference.
312+
/// If `Offset` is zero, then the next valid string offset will be fetched
313+
/// from the Offsets array, otherwise it will continue to parse the current
314+
/// entry's strings.
302315
void prepareNextStringOrEnd();
303316

304317
public:

llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,25 +321,37 @@ void AppleAcceleratorTable::Iterator::prepareNextEntryOrEnd() {
321321
}
322322

323323
void AppleAcceleratorTable::Iterator::prepareNextStringOrEnd() {
324-
std::optional<uint32_t> StrOffset = getTable().readStringOffsetAt(Offset);
324+
const AppleAcceleratorTable &Table = getTable();
325+
if (Offset == 0) {
326+
// Always start looking for strings using a valid offset from the Offsets
327+
// table. Entries are not always consecutive.
328+
std::optional<uint64_t> OptOffset = Table.readIthOffset(OffsetIdx++);
329+
if (!OptOffset)
330+
return setToEnd();
331+
Offset = *OptOffset;
332+
}
333+
std::optional<uint32_t> StrOffset = Table.readStringOffsetAt(Offset);
325334
if (!StrOffset)
326335
return setToEnd();
327336

328-
// A zero denotes the end of the collision list. Read the next string
329-
// again.
330-
if (*StrOffset == 0)
337+
// A zero denotes the end of the collision list. Skip to the next offset
338+
// in the offsets table by setting the Offset to zero so we will grab the
339+
// next offset from the offsets table.
340+
if (*StrOffset == 0) {
341+
Offset = 0;
331342
return prepareNextStringOrEnd();
343+
}
332344
Current.StrOffset = *StrOffset;
333345

334-
std::optional<uint32_t> MaybeNumEntries = getTable().readU32FromAccel(Offset);
346+
std::optional<uint32_t> MaybeNumEntries = Table.readU32FromAccel(Offset);
335347
if (!MaybeNumEntries || *MaybeNumEntries == 0)
336348
return setToEnd();
337349
NumEntriesToCome = *MaybeNumEntries;
338350
}
339351

340352
AppleAcceleratorTable::Iterator::Iterator(const AppleAcceleratorTable &Table,
341353
bool SetEnd)
342-
: Current(Table), Offset(Table.getEntriesBase()), NumEntriesToCome(0) {
354+
: Current(Table), Offset(0), NumEntriesToCome(0) {
343355
if (SetEnd)
344356
setToEnd();
345357
else

0 commit comments

Comments
 (0)