Skip to content

Commit b99a6fc

Browse files
[lldb][windows] bound ReadProcessMemory (#200230)
1 parent 76220f2 commit b99a6fc

1 file changed

Lines changed: 69 additions & 28 deletions

File tree

lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -614,44 +614,85 @@ static std::optional<std::string> GetFileNameByLoadAddress(HANDLE hProcess,
614614
return dos_path;
615615
}
616616

617+
// Determine how many bytes can be read at `addr` in `hProcess` before crossing
618+
// out of the committed memory region containing it. Returns 0 if the address is
619+
// not within a committed region.
620+
static SIZE_T BytesReadableAt(HANDLE hProcess, LPCVOID addr) {
621+
MEMORY_BASIC_INFORMATION mbi{};
622+
if (!::VirtualQueryEx(hProcess, addr, &mbi, sizeof(mbi)))
623+
return 0;
624+
if (mbi.State != MEM_COMMIT)
625+
return 0;
626+
uintptr_t region_end =
627+
reinterpret_cast<uintptr_t>(mbi.BaseAddress) + mbi.RegionSize;
628+
uintptr_t a = reinterpret_cast<uintptr_t>(addr);
629+
assert(a < region_end);
630+
return region_end - a;
631+
}
632+
633+
static std::optional<std::string> ReadRemotePathStringW(HANDLE hProcess,
634+
LPCVOID addr) {
635+
SIZE_T to_read = std::min<SIZE_T>((MAX_PATH + 1) * sizeof(wchar_t),
636+
BytesReadableAt(hProcess, addr));
637+
to_read &= ~SIZE_T(1); // round down to a wchar_t boundary
638+
if (to_read < sizeof(wchar_t))
639+
return std::nullopt;
640+
641+
std::array<wchar_t, MAX_PATH + 1> buf{};
642+
SIZE_T bytes_read = 0;
643+
if (!::ReadProcessMemory(hProcess, addr, buf.data(), to_read, &bytes_read))
644+
return std::nullopt;
645+
646+
size_t max_chars = bytes_read / sizeof(wchar_t);
647+
size_t len = ::wcsnlen(buf.data(), max_chars);
648+
if (len == max_chars) // no null terminator found
649+
return std::nullopt;
650+
if (len == 0) // empty string
651+
return std::nullopt;
652+
653+
std::string result;
654+
llvm::convertWideToUTF8(std::wstring(buf.data(), len), result);
655+
return result;
656+
}
657+
658+
static std::optional<std::string> ReadRemotePathStringA(HANDLE hProcess,
659+
LPCVOID addr) {
660+
SIZE_T to_read =
661+
std::min<SIZE_T>(MAX_PATH + 1, BytesReadableAt(hProcess, addr));
662+
if (to_read == 0)
663+
return std::nullopt;
664+
665+
std::array<char, MAX_PATH + 1> buf{};
666+
SIZE_T bytes_read = 0;
667+
if (!::ReadProcessMemory(hProcess, addr, buf.data(), to_read, &bytes_read))
668+
return std::nullopt;
669+
670+
size_t len = ::strnlen(buf.data(), bytes_read);
671+
if (len == bytes_read) // no null terminator found
672+
return std::nullopt;
673+
if (len == 0) // empty string
674+
return std::nullopt;
675+
676+
return std::string(buf.data(), len);
677+
}
678+
617679
// Resolve the LOAD_DLL_DEBUG_INFO::lpImageName field.
618680
static std::optional<std::string>
619681
GetFileNameFromImageNameField(HANDLE hProcess,
620682
const LOAD_DLL_DEBUG_INFO &info) {
621683
if (info.lpImageName == nullptr)
622684
return std::nullopt;
623685

624-
LPVOID name_addr = nullptr;
686+
LPVOID string_addr = nullptr;
625687
SIZE_T bytes_read = 0;
626-
if (!::ReadProcessMemory(hProcess, info.lpImageName, &name_addr,
627-
sizeof(name_addr), &bytes_read) ||
628-
bytes_read != sizeof(name_addr) || name_addr == nullptr)
688+
if (!::ReadProcessMemory(hProcess, info.lpImageName, &string_addr,
689+
sizeof(string_addr), &bytes_read) ||
690+
bytes_read != sizeof(string_addr))
629691
return std::nullopt;
630692

631-
if (info.fUnicode) {
632-
std::array<wchar_t, MAX_PATH + 1> wbuf{};
633-
if (!::ReadProcessMemory(hProcess, name_addr, wbuf.data(),
634-
wbuf.size() * sizeof(wchar_t), &bytes_read))
635-
return std::nullopt;
636-
if (wbuf[MAX_PATH] != L'\0')
637-
return std::nullopt;
638-
std::string path_utf8;
639-
llvm::convertWideToUTF8(wbuf.data(), path_utf8);
640-
if (path_utf8.empty())
641-
return std::nullopt;
642-
return path_utf8;
643-
}
644-
645-
std::array<char, MAX_PATH + 1> abuf{};
646-
if (!::ReadProcessMemory(hProcess, name_addr, abuf.data(), abuf.size(),
647-
&bytes_read))
648-
return std::nullopt;
649-
if (abuf[MAX_PATH] != '\0')
650-
return std::nullopt;
651-
std::string path(abuf.data());
652-
if (path.empty())
653-
return std::nullopt;
654-
return path;
693+
if (info.fUnicode)
694+
return ReadRemotePathStringW(hProcess, string_addr);
695+
return ReadRemotePathStringA(hProcess, string_addr);
655696
}
656697

657698
DWORD

0 commit comments

Comments
 (0)