Skip to content

[lldb] Replace PathMappingList::GetPathsAtIndex with thread-safe alternative #147396

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

bulbazord
Copy link
Member

Iteration by index is not thread-safe with PathMapingList's design. Instead, we can expose a ForEach method that grabs the PathMappingList's lock before the callback.

There is a potential pitfall here where the callback tries to call another PathMappingList method (causing a deadlock), but that seems a little easier to debug than the PathMappingList getting updated in the middle of a loop somewhere.

…rnative

Iteration by index is not thread-safe with PathMapingList's design.
Instead, we can expose a `ForEach` method that grabs the
PathMappingList's lock before the callback.

There is a potential pitfall here where the callback tries to call
another PathMappingList method (causing a deadlock), but that seems a
little to debug than the PathMappingList getting updated in the middle
of a loop somewhere.
@bulbazord bulbazord requested a review from JDevlieghere as a code owner July 7, 2025 20:57
@llvmbot llvmbot added the lldb label Jul 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 7, 2025

@llvm/pr-subscribers-lldb

Author: Alex Langford (bulbazord)

Changes

Iteration by index is not thread-safe with PathMapingList's design. Instead, we can expose a ForEach method that grabs the PathMappingList's lock before the callback.

There is a potential pitfall here where the callback tries to call another PathMappingList method (causing a deadlock), but that seems a little easier to debug than the PathMappingList getting updated in the middle of a loop somewhere.


Full diff: https://github.com/llvm/llvm-project/pull/147396.diff

3 Files Affected:

  • (modified) lldb/include/lldb/Target/PathMappingList.h (+4-2)
  • (modified) lldb/source/Commands/CommandObjectTarget.cpp (+11-9)
  • (modified) lldb/source/Target/PathMappingList.cpp (+5-8)
diff --git a/lldb/include/lldb/Target/PathMappingList.h b/lldb/include/lldb/Target/PathMappingList.h
index 2cf9569358f52..02fee4d8ed45f 100644
--- a/lldb/include/lldb/Target/PathMappingList.h
+++ b/lldb/include/lldb/Target/PathMappingList.h
@@ -61,8 +61,10 @@ class PathMappingList {
     return m_pairs.size();
   }
 
-  bool GetPathsAtIndex(uint32_t idx, ConstString &path,
-                       ConstString &new_path) const;
+  /// Invokes callback for each pair of paths in the list. The callback can
+  /// return false to immediately stop iteration.
+  void
+  ForEach(std::function<bool(llvm::StringRef, llvm::StringRef)> callback) const;
 
   void Insert(llvm::StringRef path, llvm::StringRef replacement,
               uint32_t insert_idx, bool notify);
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index fe421adfe8709..e8ebcb8008ff9 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -1139,15 +1139,17 @@ class CommandObjectTargetModulesSearchPathsInsert : public CommandObjectParsed {
 
     Target *target = m_exe_ctx.GetTargetPtr();
     const PathMappingList &list = target->GetImageSearchPathList();
-    const size_t num = list.GetSize();
-    ConstString old_path, new_path;
-    for (size_t i = 0; i < num; ++i) {
-      if (!list.GetPathsAtIndex(i, old_path, new_path))
-        break;
-      StreamString strm;
-      strm << old_path << " -> " << new_path;
-      request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
-    }
+
+    StreamString strm;
+    size_t index = 0;
+    list.ForEach([&](llvm::StringRef orig_path, llvm::StringRef remap_path) {
+      strm << orig_path << " -> " << remap_path;
+      request.TryCompleteCurrentArg(std::to_string(index), strm.GetString());
+
+      index++;
+      strm.Clear();
+      return true;
+    });
   }
 
 protected:
diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp
index 0465b4280bbb1..d8dd9dde7a307 100644
--- a/lldb/source/Target/PathMappingList.cpp
+++ b/lldb/source/Target/PathMappingList.cpp
@@ -346,15 +346,12 @@ PathMappingList::FindIteratorForPath(ConstString path) {
   return pos;
 }
 
-bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
-                                      ConstString &new_path) const {
+void PathMappingList::ForEach(
+    std::function<bool(llvm::StringRef, llvm::StringRef)> callback) const {
   std::lock_guard<std::mutex> lock(m_pairs_mutex);
-  if (idx < m_pairs.size()) {
-    path = m_pairs[idx].first;
-    new_path = m_pairs[idx].second;
-    return true;
-  }
-  return false;
+  for (const auto &[original, replacement] : m_pairs)
+    if (!callback(original, replacement))
+      break;
 }
 
 uint32_t

ConstString &new_path) const;
/// Invokes callback for each pair of paths in the list. The callback can
/// return false to immediately stop iteration.
void ForEach(std::function<bool(size_t, llvm::StringRef, llvm::StringRef)>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this method used a lot? Could we migrate to using the LockingAdaptedIterable instead of match how other classes handle this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only used in one place. I'll look at LockingAdaptedIterable and see how bad it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants