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

Reply via email to