llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Charles Zablit (charles-zablit) <details> <summary>Changes</summary> `DebuggerThread.cpp` relied on `MAX_PATH` (260 characters) to allocate buffers for file paths. This leads to truncation of paths that are longer than that. This patch allows longer path (up to the `0x8000` unicode limit). --- Full diff: https://github.com/llvm/llvm-project/pull/206114.diff 1 Files Affected: - (modified) lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp (+79-63) ``````````diff diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index ce679d905a734..c109086a67c46 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -548,6 +548,25 @@ ConvertNtDevicePathToDosPath(llvm::ArrayRef<wchar_t> nt_path) { return std::nullopt; } +// Query the file name backing the mapping at `addr` in `process` and convert +// the resulting NT device path to a DOS path. +static std::optional<std::string> GetMappedFileDosPath(HANDLE process, + LPVOID addr) { + std::vector<wchar_t> mapped_filename(MAX_PATH + 1); + DWORD mapped_len = 0; + while (mapped_filename.size() <= PATHCCH_MAX_CCH) { + mapped_len = ::GetMappedFileNameW(process, addr, mapped_filename.data(), + mapped_filename.size()); + if (mapped_len == 0) + return std::nullopt; + if (mapped_len < mapped_filename.size()) + break; + mapped_filename.resize(mapped_filename.size() * 2); + } + return ConvertNtDevicePathToDosPath( + llvm::ArrayRef<wchar_t>(mapped_filename.data(), mapped_len + 1)); +} + static std::optional<std::string> GetFileNameFromHandleFallback(HANDLE hFile) { // Check that file is not empty as we cannot map a file with zero length. DWORD dwFileSizeHi = 0; @@ -567,42 +586,29 @@ static std::optional<std::string> GetFileNameFromHandleFallback(HANDLE hFile) { if (!pMem) return std::nullopt; - std::array<wchar_t, MAX_PATH + 1> mapped_filename; - if (!::GetMappedFileNameW(::GetCurrentProcess(), pMem.get(), - mapped_filename.data(), mapped_filename.size())) - return std::nullopt; - - return ConvertNtDevicePathToDosPath(mapped_filename); + return GetMappedFileDosPath(::GetCurrentProcess(), pMem.get()); } static std::optional<std::string> GetFileNameByLoadAddress(HANDLE process, LPVOID base_addr) { - std::array<wchar_t, MAX_PATH + 1> module_filename; - DWORD len = - ::GetModuleFileNameExW(process, reinterpret_cast<HMODULE>(base_addr), - module_filename.data(), module_filename.size()); - if (len > 0 && len < module_filename.size()) { - std::string path_utf8; - llvm::convertWideToUTF8(std::wstring(module_filename.data(), len), - path_utf8); - return path_utf8; + std::vector<wchar_t> module_filename(MAX_PATH + 1); + while (module_filename.size() <= PATHCCH_MAX_CCH) { + DWORD len = + ::GetModuleFileNameExW(process, reinterpret_cast<HMODULE>(base_addr), + module_filename.data(), module_filename.size()); + if (len == 0) + break; // Not loaded as a module; fall back to the mapped-file query. + if (len < module_filename.size()) { + std::string path_utf8; + llvm::convertWideToUTF8(std::wstring(module_filename.data(), len), + path_utf8); + return path_utf8; + } + module_filename.resize(module_filename.size() * 2); } // Fallback: ask the kernel for the file backing the mapping at this address. - std::vector<wchar_t> mapped_filename(MAX_PATH + 1); - DWORD mapped_len = 0; - while (mapped_filename.size() <= PATHCCH_MAX_CCH) { - mapped_len = ::GetMappedFileNameW( - process, base_addr, mapped_filename.data(), mapped_filename.size()); - if (mapped_len < mapped_filename.size()) - break; - if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return std::nullopt; - mapped_filename.resize(mapped_filename.size() * 2); - } - std::optional<std::string> dos_path = ConvertNtDevicePathToDosPath( - llvm::ArrayRef<wchar_t>(mapped_filename.data(), mapped_len + 1)); - return dos_path; + return GetMappedFileDosPath(process, base_addr); } // Determine how many bytes can be read at `addr` in `process` before crossing @@ -623,48 +629,58 @@ static SIZE_T BytesReadableAt(HANDLE process, LPCVOID addr) { static std::optional<std::string> ReadRemotePathStringW(HANDLE process, LPCVOID addr) { - SIZE_T to_read = std::min<SIZE_T>((MAX_PATH + 1) * sizeof(wchar_t), - BytesReadableAt(process, addr)); - to_read &= ~SIZE_T(1); // round down to a wchar_t boundary - if (to_read < sizeof(wchar_t)) - return std::nullopt; - - std::array<wchar_t, MAX_PATH + 1> buf{}; - SIZE_T bytes_read = 0; - if (!::ReadProcessMemory(process, addr, buf.data(), to_read, &bytes_read)) - return std::nullopt; + SIZE_T limit = std::min<SIZE_T>(PATHCCH_MAX_CCH * sizeof(wchar_t), + BytesReadableAt(process, addr)); + std::vector<wchar_t> buf; + for (SIZE_T capacity = MAX_PATH * sizeof(wchar_t);; capacity *= 2) { + SIZE_T to_read = std::min<SIZE_T>(capacity, limit); + to_read &= ~SIZE_T(1); // round down to a wchar_t boundary + if (to_read < sizeof(wchar_t)) + return std::nullopt; - size_t max_chars = bytes_read / sizeof(wchar_t); - size_t len = ::wcsnlen(buf.data(), max_chars); - if (len == max_chars) // no null terminator found - return std::nullopt; - if (len == 0) // empty string - return std::nullopt; + buf.resize(to_read / sizeof(wchar_t)); + SIZE_T bytes_read = 0; + if (!::ReadProcessMemory(process, addr, buf.data(), to_read, &bytes_read)) + return std::nullopt; - std::string result; - llvm::convertWideToUTF8(std::wstring(buf.data(), len), result); - return result; + size_t max_chars = bytes_read / sizeof(wchar_t); + size_t len = ::wcsnlen(buf.data(), max_chars); + if (len < max_chars) { // found the null terminator + if (len == 0) // empty string + return std::nullopt; + std::string result; + llvm::convertWideToUTF8(std::wstring(buf.data(), len), result); + return result; + } + if (to_read >= limit) // read everything available without a terminator + return std::nullopt; + } } static std::optional<std::string> ReadRemotePathStringA(HANDLE process, LPCVOID addr) { - SIZE_T to_read = - std::min<SIZE_T>(MAX_PATH + 1, BytesReadableAt(process, addr)); - if (to_read == 0) - return std::nullopt; - - std::array<char, MAX_PATH + 1> buf{}; - SIZE_T bytes_read = 0; - if (!::ReadProcessMemory(process, addr, buf.data(), to_read, &bytes_read)) - return std::nullopt; + SIZE_T limit = + std::min<SIZE_T>(PATHCCH_MAX_CCH, BytesReadableAt(process, addr)); + std::vector<char> buf; + for (SIZE_T capacity = MAX_PATH;; capacity *= 2) { + SIZE_T to_read = std::min<SIZE_T>(capacity, limit); + if (to_read == 0) + return std::nullopt; - size_t len = ::strnlen(buf.data(), bytes_read); - if (len == bytes_read) // no null terminator found - return std::nullopt; - if (len == 0) // empty string - return std::nullopt; + buf.resize(to_read); + SIZE_T bytes_read = 0; + if (!::ReadProcessMemory(process, addr, buf.data(), to_read, &bytes_read)) + return std::nullopt; - return std::string(buf.data(), len); + size_t len = ::strnlen(buf.data(), bytes_read); + if (len < bytes_read) { // found the null terminator + if (len == 0) // empty string + return std::nullopt; + return std::string(buf.data(), len); + } + if (to_read >= limit) // read everything available without a terminator + return std::nullopt; + } } // Resolve the LOAD_DLL_DEBUG_INFO::lpImageName field. `````````` </details> https://github.com/llvm/llvm-project/pull/206114 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
