Skip to content

[lldb][Expression] Allow specifying a preferred ModuleList for lookup during expression evaluation #129733

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

Merged
merged 6 commits into from
Mar 6, 2025

Conversation

Michael137
Copy link
Member

@Michael137 Michael137 commented Mar 4, 2025

The TestMemoryHistory.py/TestReportData.py are currently failing on the x86 macOS CI (started after we upgraded the Xcode SDK on that machien). The LLDB ASAN utility expression is failing to run with following error:

(lldb) image lookup -n __asan_get_alloc_stack
1 match found in /usr/lib/system/libsystem_sanitizers.dylib:
        Address: libsystem_sanitizers.dylib[0x00007ffd11e673f7] (libsystem_sanitizers.dylib.__TEXT.__text + 11287)
        Summary: libsystem_sanitizers.dylib`__asan_get_alloc_stack
1 match found in /Users/michaelbuch/Git/lldb-build-main-no-modules/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:
        Address: libclang_rt.asan_osx_dynamic.dylib[0x0000000000009ec0] (libclang_rt.asan_osx_dynamic.dylib.__TEXT.__text + 34352)
        Summary: libclang_rt.asan_osx_dynamic.dylib`::__asan_get_alloc_stack(__sanitizer::uptr, __sanitizer::uptr *, __sanitizer::uptr, __sanitizer::u32 *) at asan_debugging.cpp:132
(lldb) memory history 'pointer'
Assertion failed: ((uintptr_t)addr == report.access.address), function __asan_get_alloc_stack, file debugger_abi.cpp, line 62.
warning: cannot evaluate AddressSanitizer expression:
error: Expression execution was interrupted: signal SIGABRT.
The process has been returned to the state before expression evaluation.

The reason for this is that the system sanitizer dylib and the locally built libclang_rt contain the same symbol __asan_get_alloc_stack, and depending on the order in which they're loaded, we may pick the one from the wrong dylib (this probably changed during the buildbot upgrade and is why it only now started failing). Based on discussion with @wrotki we always want to pick the one that's in the libclang_rt dylib if it was loaded, and libsystem_sanitizers otherwise.

This patch addresses this by adding a "preferred lookup context list" to the expression evaluator. Currently this is only exposed in the EvaluateExpressionOptions. We make it a SymbolContextList in case we want the lookup contexts to be contexts other than modules (e.g., source files, etc.). In IRExecutionUnit we make it a ModuleList because it makes the symbol lookup implementation simpler and we only do module lookups here anyway. If we ever need it to be a SymbolContext, that transformation shouldn't be too difficult.

@Michael137 Michael137 requested a review from adrian-prantl March 4, 2025 16:24
const auto &target = process_sp->GetTarget();
std::unordered_set<ModuleSP> preferred_modules;
target.GetImages().ForEach([&](const lldb::ModuleSP &m) {
llvm::Regex pattern("libclang_rt.asan_.*_dynamic.dylib");
Copy link
Member Author

Choose a reason for hiding this comment

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

@wrotki is this going to hold in the long-term? Will the locally built compiler-rt always be libclang_rt?

Copy link
Contributor

@wrotki wrotki Mar 4, 2025

Choose a reason for hiding this comment

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

libclang_rt is here to stay forever I believe.

Can you escape literal dots in the regex (i.e. to be libclang_rt\.asan_.*_dynamic\.dylib) ? As it is, they're matching any character, which is not intended.

@jimingham
Copy link
Collaborator

I think it would be better to structure this as a list of SymbolContext's that we search in order, not a set of modules. We keep talking about inventing some syntax in an identifier in the expression parser to say "foo from bar in baz.c", but we never have come up with something workable. The cheap alternative to that is to allow people to specify a list of places to search first when resolving symbols. The places in that list might be a module, but also might be a file or a function, so SymbolContext would be a better container. And it will be more useful if the order were significant. Then at some point we can enhance the expr command so you can do:

expr -s foo.dylib -f bar.c -n baz -- <expression>
That would look first for names in foo.dylib, stopping if it finds a match, then in bar.c, then in the baz.

@Michael137 Michael137 marked this pull request as ready for review March 5, 2025 12:43
@Michael137 Michael137 requested a review from JDevlieghere as a code owner March 5, 2025 12:43
@llvmbot llvmbot added the lldb label Mar 5, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 5, 2025

@llvm/pr-subscribers-lldb

Author: Michael Buch (Michael137)

Changes

The TestMemoryHistory.py is currently failing on the x86 macOS CI. The LLDB ASAN utility expression is failing to run with following error:

(lldb) image lookup -n __asan_get_alloc_stack
1 match found in /usr/lib/system/libsystem_sanitizers.dylib:
        Address: libsystem_sanitizers.dylib[0x00007ffd11e673f7] (libsystem_sanitizers.dylib.__TEXT.__text + 11287)
        Summary: libsystem_sanitizers.dylib`__asan_get_alloc_stack
1 match found in /Users/michaelbuch/Git/lldb-build-main-no-modules/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:
        Address: libclang_rt.asan_osx_dynamic.dylib[0x0000000000009ec0] (libclang_rt.asan_osx_dynamic.dylib.__TEXT.__text + 34352)
        Summary: libclang_rt.asan_osx_dynamic.dylib`::__asan_get_alloc_stack(__sanitizer::uptr, __sanitizer::uptr *, __sanitizer::uptr, __sanitizer::u32 *) at asan_debugging.cpp:132
(lldb) memory history 'pointer'
Assertion failed: ((uintptr_t)addr == report.access.address), function __asan_get_alloc_stack, file debugger_abi.cpp, line 62.
warning: cannot evaluate AddressSanitizer expression:
error: Expression execution was interrupted: signal SIGABRT.
The process has been returned to the state before expression evaluation.

The reason for this is that the system sanitizer dylib and the locally built libclang_rt contain the same symbol __asan_get_alloc_stack, and depending on the order in which they're loaded we pick the one from the wrong dylib. Based on discussion with @wrotki we always want to pick the one that's in the libclang_rt dylib if it was loaded, and libsystem_sanitizers otherwise.

This patch addresses this by adding a "preferred lookup context list" to the expression evaluator. Currently this is only exposed in the EvaluateExpressionOptions. We make it a SymbolContextList in case we want the lookup contexts to be contexts other than modules (e.g., source files, etc.). In IRExecutionUnit we make it a ModuleList because it makes the symbol lookup implementation simpler and we only do module lookups here anyway. If we ever need it to be a SymbolContext, that transformation shouldn't be too difficult.


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

5 Files Affected:

  • (modified) lldb/include/lldb/Expression/IRExecutionUnit.h (+12)
  • (modified) lldb/include/lldb/Target/Target.h (+14)
  • (modified) lldb/source/Expression/IRExecutionUnit.cpp (+26-5)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+4)
  • (modified) lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp (+26)
diff --git a/lldb/include/lldb/Expression/IRExecutionUnit.h b/lldb/include/lldb/Expression/IRExecutionUnit.h
index 58f12bf8b64f5..77d53daf80c1b 100644
--- a/lldb/include/lldb/Expression/IRExecutionUnit.h
+++ b/lldb/include/lldb/Expression/IRExecutionUnit.h
@@ -17,6 +17,7 @@
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 #include "llvm/IR/Module.h"
 
+#include "lldb/Core/ModuleList.h"
 #include "lldb/Expression/IRMemoryMap.h"
 #include "lldb/Expression/ObjectFileJIT.h"
 #include "lldb/Symbol/SymbolContext.h"
@@ -161,6 +162,12 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
     return m_jitted_global_variables;
   }
 
+  void SetPreferredModules(SymbolContextList const &modules) {
+    for (auto const &m : modules)
+      if (m.module_sp)
+        m_preferred_modules.Append(m.module_sp);
+  }
+
 private:
   /// Look up the object in m_address_map that contains a given address, find
   /// where it was copied to, and return the remote address at the same offset
@@ -396,6 +403,11 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
   ///< defining no functions using that variable, would do this.)  If this
   ///< is true, any allocations need to be committed immediately -- no
   ///< opportunity for relocation.
+
+  ///< Any Module in this list will be used for symbol/function lookup
+  ///< before any other module (except for the module corresponding to the
+  ///< current frame).
+  ModuleList m_preferred_modules;
 };
 
 } // namespace lldb_private
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index f31ac381391b4..a4059cdb2a819 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -25,6 +25,7 @@
 #include "lldb/Core/UserSettingsController.h"
 #include "lldb/Expression/Expression.h"
 #include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Symbol/TypeSystem.h"
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/PathMappingList.h"
@@ -332,6 +333,14 @@ class EvaluateExpressionOptions {
     m_language = SourceLanguage(language_type);
   }
 
+  void SetPreferredSymbolContexts(SymbolContextList modules) {
+    m_preferred_lookup_contexts = std::move(modules);
+  }
+
+  const SymbolContextList &GetPreferredSymbolContexts() const {
+    return m_preferred_lookup_contexts;
+  }
+
   /// Set the language using a pair of language code and version as
   /// defined by the DWARF 6 specification.
   /// WARNING: These codes may change until DWARF 6 is finalized.
@@ -500,6 +509,11 @@ class EvaluateExpressionOptions {
   // originates
   mutable std::string m_pound_line_file;
   mutable uint32_t m_pound_line_line = 0;
+
+  ///< During expression evaluation, any SymbolContext in this list will be
+  ///< used for symbol/function lookup before any other context (except for
+  ///< the module corresponding to the current frame).
+  SymbolContextList m_preferred_lookup_contexts;
 };
 
 // Target
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index c8b4ddf705ec4..06b0cb7769f64 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -52,7 +52,7 @@ IRExecutionUnit::IRExecutionUnit(std::unique_ptr<llvm::LLVMContext> &context_up,
       m_cpu_features(cpu_features), m_name(name), m_sym_ctx(sym_ctx),
       m_did_jit(false), m_function_load_addr(LLDB_INVALID_ADDRESS),
       m_function_end_load_addr(LLDB_INVALID_ADDRESS),
-      m_reported_allocations(false) {}
+      m_reported_allocations(false), m_preferred_modules() {}
 
 lldb::addr_t IRExecutionUnit::WriteNow(const uint8_t *bytes, size_t size,
                                        Status &error) {
@@ -782,8 +782,11 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
   }
 
   ModuleList non_local_images = target->GetImages();
-  // We'll process module_sp separately, before the other modules.
+  // We'll process module_sp and any preferred modules separately, before the
+  // other modules.
   non_local_images.Remove(sc.module_sp);
+  for (size_t i = 0; i < m_preferred_modules.GetSize(); ++i)
+    non_local_images.Remove(m_preferred_modules.GetModuleAtIndex(i));
 
   LoadAddressResolver resolver(target, symbol_was_missing_weak);
 
@@ -794,9 +797,11 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
   for (const ConstString &name : names) {
     // The lookup order here is as follows:
     // 1) Functions in `sc.module_sp`
-    // 2) Functions in the other modules
-    // 3) Symbols in `sc.module_sp`
-    // 4) Symbols in the other modules
+    // 2) Functions in the preferred modules list
+    // 3) Functions in the other modules
+    // 4) Symbols in `sc.module_sp`
+    // 5) Symbols in the preferred modules list
+    // 6) Symbols in the other modules
     if (sc.module_sp) {
       SymbolContextList sc_list;
       sc.module_sp->FindFunctions(name, CompilerDeclContext(),
@@ -806,6 +811,14 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
         return *load_addr;
     }
 
+    {
+      SymbolContextList sc_list;
+      m_preferred_modules.FindFunctions(name, lldb::eFunctionNameTypeFull,
+                                        function_options, sc_list);
+      if (auto load_addr = resolver.Resolve(sc_list))
+        return *load_addr;
+    }
+
     {
       SymbolContextList sc_list;
       non_local_images.FindFunctions(name, lldb::eFunctionNameTypeFull,
@@ -822,6 +835,14 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
         return *load_addr;
     }
 
+    {
+      SymbolContextList sc_list;
+      m_preferred_modules.FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
+                                                     sc_list);
+      if (auto load_addr = resolver.Resolve(sc_list))
+        return *load_addr;
+    }
+
     {
       SymbolContextList sc_list;
       non_local_images.FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index f1573bae2651b..cefa226175855 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -1539,6 +1539,10 @@ lldb_private::Status ClangExpressionParser::DoPrepareForExecution(
       function_name, exe_ctx.GetTargetSP(), sc,
       m_compiler->getTargetOpts().Features);
 
+  if (auto *options = m_expr.GetOptions())
+    execution_unit_sp->SetPreferredModules(
+        options->GetPreferredSymbolContexts());
+
   ClangExpressionHelper *type_system_helper =
       dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
   ClangExpressionDeclMap *decl_map =
diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
index 41df0e85199ce..b806bbf15ac5f 100644
--- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
+++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
@@ -8,6 +8,7 @@
 
 #include "MemoryHistoryASan.h"
 
+#include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Target/MemoryHistory.h"
 
 #include "Plugins/Process/Utility/HistoryThread.h"
@@ -61,6 +62,25 @@ MemoryHistoryASan::MemoryHistoryASan(const ProcessSP &process_sp) {
     m_process_wp = process_sp;
 }
 
+///< On Darwin, if LLDB loaded libclang_rt, it's coming from a locally built
+///< compiler-rt, and we should prefer it in favour of the system sanitizers.
+///< This helper searches the target for such a dylib. Returns nullptr if no
+///< such dylib was found.
+static ModuleSP GetPreferredAsanModule(const Target &target) {
+  ModuleSP module;
+  llvm::Regex pattern(R"(libclang_rt\.asan_.*_dynamic\.dylib)");
+  target.GetImages().ForEach([&](const lldb::ModuleSP &m) {
+    if (pattern.match(m->GetFileSpec().GetFilename().GetStringRef())) {
+      module = m;
+      return false;
+    }
+
+    return true;
+  });
+
+  return module;
+}
+
 const char *memory_history_asan_command_prefix = R"(
     extern "C"
     {
@@ -174,6 +194,12 @@ HistoryThreads MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address) {
   options.SetAutoApplyFixIts(false);
   options.SetLanguage(eLanguageTypeObjC_plus_plus);
 
+  if (auto m = GetPreferredAsanModule(process_sp->GetTarget())) {
+    SymbolContextList sc_list;
+    sc_list.Append(SymbolContext(std::move(m)));
+    options.SetPreferredSymbolContexts(std::move(sc_list));
+  }
+
   ExpressionResults expr_result = UserExpression::Evaluate(
       exe_ctx, options, expr.GetString(), "", return_value_sp);
   if (expr_result != eExpressionCompleted) {

@Michael137 Michael137 requested a review from jimingham March 5, 2025 12:44
@Michael137
Copy link
Member Author

Just realized we also need to adjust ReportRetriever.cpp to use the preferred module since it runs an ASAN utility expression

@@ -161,6 +162,12 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
return m_jitted_global_variables;
}

void SetPreferredModules(SymbolContextList const &modules) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is called SetPreferredModules but is actually AppendToPreferredModules.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, these are no longer modules you should change the names to reflect that.

@@ -396,6 +403,11 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
///< defining no functions using that variable, would do this.) If this
///< is true, any allocations need to be committed immediately -- no
///< opportunity for relocation.

///< Any Module in this list will be used for symbol/function lookup
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again, no longer Modules...

@@ -332,6 +333,14 @@ class EvaluateExpressionOptions {
m_language = SourceLanguage(language_type);
}

void SetPreferredSymbolContexts(SymbolContextList modules) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not modules

@jimingham
Copy link
Collaborator

You should complete the module -> symbol_context mutatis mutandis. Other than that this seems like the right foundation for adding a user way to control the symbol lookups.

@Michael137
Copy link
Member Author

You should complete the module -> symbol_context mutatis mutandis. Other than that this seems like the right foundation for adding a user way to control the symbol lookups.

I kept the list of preferred contexts as a ModuleList in IRExecutionUnit. That's why I kept Module in the name where it applies. It made the implementation of the lookup easier (because ModuleList already has the symbol lookup APIs that we need). I discuss this a bit more in the PR description. Let me know what you think

@jimingham
Copy link
Collaborator

You should complete the module -> symbol_context mutatis mutandis. Other than that this seems like the right foundation for adding a user way to control the symbol lookups.

I kept the list of preferred contexts as a ModuleList in IRExecutionUnit. That's why I kept Module in the name where it applies. It made the implementation of the lookup easier (because ModuleList already has the symbol lookup APIs that we need). I discuss this a bit more in the PR description. Let me know what you think

Makes sense, the other searches happen earlier on in parsing, so that should be okay. But you still have in a couple of places:

void SetPreferredModules(SymbolContextList const &modules) {

And then it looks really weird when you iterate over modules and pull out m.module_sp???

@Michael137
Copy link
Member Author

You should complete the module -> symbol_context mutatis mutandis. Other than that this seems like the right foundation for adding a user way to control the symbol lookups.

I kept the list of preferred contexts as a ModuleList in IRExecutionUnit. That's why I kept Module in the name where it applies. It made the implementation of the lookup easier (because ModuleList already has the symbol lookup APIs that we need). I discuss this a bit more in the PR description. Let me know what you think

Makes sense, the other searches happen earlier on in parsing, so that should be okay. But you still have in a couple of places:

void SetPreferredModules(SymbolContextList const &modules) {

And then it looks really weird when you iterate over modules and pull out m.module_sp???

sounds good, i renamed those in the latest commit

Let me know if i missed anything

Copy link
Collaborator

@jimingham jimingham left a comment

Choose a reason for hiding this comment

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

LGTM

Should maybe file an ER on the lldb issues to plumb this (and the other SymbolContext specifications) through the expression command so some ambitious person could see and do that.

@Michael137 Michael137 merged commit 542d52b into llvm:main Mar 6, 2025
10 checks passed
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Mar 20, 2025
… during expression evaluation (llvm#129733)

The `TestMemoryHistory.py`/`TestReportData.py` are currently failing on
the x86 macOS CI (started after we upgraded the Xcode SDK on that
machien). The LLDB ASAN utility expression is failing to run with
following error:
```
(lldb) image lookup -n __asan_get_alloc_stack
1 match found in /usr/lib/system/libsystem_sanitizers.dylib:
        Address: libsystem_sanitizers.dylib[0x00007ffd11e673f7] (libsystem_sanitizers.dylib.__TEXT.__text + 11287)
        Summary: libsystem_sanitizers.dylib`__asan_get_alloc_stack
1 match found in /Users/michaelbuch/Git/lldb-build-main-no-modules/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:
        Address: libclang_rt.asan_osx_dynamic.dylib[0x0000000000009ec0] (libclang_rt.asan_osx_dynamic.dylib.__TEXT.__text + 34352)
        Summary: libclang_rt.asan_osx_dynamic.dylib`::__asan_get_alloc_stack(__sanitizer::uptr, __sanitizer::uptr *, __sanitizer::uptr, __sanitizer::u32 *) at asan_debugging.cpp:132
(lldb) memory history 'pointer'
Assertion failed: ((uintptr_t)addr == report.access.address), function __asan_get_alloc_stack, file debugger_abi.cpp, line 62.
warning: cannot evaluate AddressSanitizer expression:
error: Expression execution was interrupted: signal SIGABRT.
The process has been returned to the state before expression evaluation.
```

The reason for this is that the system sanitizer dylib and the locally
built libclang_rt contain the same symbol `__asan_get_alloc_stack`, and
depending on the order in which they're loaded, we may pick the one from
the wrong dylib (this probably changed during the buildbot upgrade and
is why it only now started failing). Based on discussion with @wrotki we
always want to pick the one that's in the libclang_rt dylib if it was
loaded, and libsystem_sanitizers otherwise.

This patch addresses this by adding a "preferred lookup context list" to
the expression evaluator. Currently this is only exposed in the
`EvaluateExpressionOptions`. We make it a `SymbolContextList` in case we
want the lookup contexts to be contexts other than modules (e.g., source
files, etc.). In `IRExecutionUnit` we make it a `ModuleList` because it
makes the symbol lookup implementation simpler and we only do module
lookups here anyway. If we ever need it to be a `SymbolContext`, that
transformation shouldn't be too difficult.

(cherry picked from commit 542d52b)
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
… during expression evaluation (llvm#129733)

The `TestMemoryHistory.py`/`TestReportData.py` are currently failing on
the x86 macOS CI (started after we upgraded the Xcode SDK on that
machien). The LLDB ASAN utility expression is failing to run with
following error:
```
(lldb) image lookup -n __asan_get_alloc_stack
1 match found in /usr/lib/system/libsystem_sanitizers.dylib:
        Address: libsystem_sanitizers.dylib[0x00007ffd11e673f7] (libsystem_sanitizers.dylib.__TEXT.__text + 11287)
        Summary: libsystem_sanitizers.dylib`__asan_get_alloc_stack
1 match found in /Users/michaelbuch/Git/lldb-build-main-no-modules/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:
        Address: libclang_rt.asan_osx_dynamic.dylib[0x0000000000009ec0] (libclang_rt.asan_osx_dynamic.dylib.__TEXT.__text + 34352)
        Summary: libclang_rt.asan_osx_dynamic.dylib`::__asan_get_alloc_stack(__sanitizer::uptr, __sanitizer::uptr *, __sanitizer::uptr, __sanitizer::u32 *) at asan_debugging.cpp:132
(lldb) memory history 'pointer'
Assertion failed: ((uintptr_t)addr == report.access.address), function __asan_get_alloc_stack, file debugger_abi.cpp, line 62.
warning: cannot evaluate AddressSanitizer expression:
error: Expression execution was interrupted: signal SIGABRT.
The process has been returned to the state before expression evaluation.
```

The reason for this is that the system sanitizer dylib and the locally
built libclang_rt contain the same symbol `__asan_get_alloc_stack`, and
depending on the order in which they're loaded, we may pick the one from
the wrong dylib (this probably changed during the buildbot upgrade and
is why it only now started failing). Based on discussion with @wrotki we
always want to pick the one that's in the libclang_rt dylib if it was
loaded, and libsystem_sanitizers otherwise.

This patch addresses this by adding a "preferred lookup context list" to
the expression evaluator. Currently this is only exposed in the
`EvaluateExpressionOptions`. We make it a `SymbolContextList` in case we
want the lookup contexts to be contexts other than modules (e.g., source
files, etc.). In `IRExecutionUnit` we make it a `ModuleList` because it
makes the symbol lookup implementation simpler and we only do module
lookups here anyway. If we ever need it to be a `SymbolContext`, that
transformation shouldn't be too difficult.
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Mar 24, 2025
… during expression evaluation (llvm#129733)

The `TestMemoryHistory.py`/`TestReportData.py` are currently failing on
the x86 macOS CI (started after we upgraded the Xcode SDK on that
machien). The LLDB ASAN utility expression is failing to run with
following error:
```
(lldb) image lookup -n __asan_get_alloc_stack
1 match found in /usr/lib/system/libsystem_sanitizers.dylib:
        Address: libsystem_sanitizers.dylib[0x00007ffd11e673f7] (libsystem_sanitizers.dylib.__TEXT.__text + 11287)
        Summary: libsystem_sanitizers.dylib`__asan_get_alloc_stack
1 match found in /Users/michaelbuch/Git/lldb-build-main-no-modules/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:
        Address: libclang_rt.asan_osx_dynamic.dylib[0x0000000000009ec0] (libclang_rt.asan_osx_dynamic.dylib.__TEXT.__text + 34352)
        Summary: libclang_rt.asan_osx_dynamic.dylib`::__asan_get_alloc_stack(__sanitizer::uptr, __sanitizer::uptr *, __sanitizer::uptr, __sanitizer::u32 *) at asan_debugging.cpp:132
(lldb) memory history 'pointer'
Assertion failed: ((uintptr_t)addr == report.access.address), function __asan_get_alloc_stack, file debugger_abi.cpp, line 62.
warning: cannot evaluate AddressSanitizer expression:
error: Expression execution was interrupted: signal SIGABRT.
The process has been returned to the state before expression evaluation.
```

The reason for this is that the system sanitizer dylib and the locally
built libclang_rt contain the same symbol `__asan_get_alloc_stack`, and
depending on the order in which they're loaded, we may pick the one from
the wrong dylib (this probably changed during the buildbot upgrade and
is why it only now started failing). Based on discussion with @wrotki we
always want to pick the one that's in the libclang_rt dylib if it was
loaded, and libsystem_sanitizers otherwise.

This patch addresses this by adding a "preferred lookup context list" to
the expression evaluator. Currently this is only exposed in the
`EvaluateExpressionOptions`. We make it a `SymbolContextList` in case we
want the lookup contexts to be contexts other than modules (e.g., source
files, etc.). In `IRExecutionUnit` we make it a `ModuleList` because it
makes the symbol lookup implementation simpler and we only do module
lookups here anyway. If we ever need it to be a `SymbolContext`, that
transformation shouldn't be too difficult.

(cherry picked from commit 542d52b)
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Mar 24, 2025
… during expression evaluation (llvm#129733)

The `TestMemoryHistory.py`/`TestReportData.py` are currently failing on
the x86 macOS CI (started after we upgraded the Xcode SDK on that
machien). The LLDB ASAN utility expression is failing to run with
following error:
```
(lldb) image lookup -n __asan_get_alloc_stack
1 match found in /usr/lib/system/libsystem_sanitizers.dylib:
        Address: libsystem_sanitizers.dylib[0x00007ffd11e673f7] (libsystem_sanitizers.dylib.__TEXT.__text + 11287)
        Summary: libsystem_sanitizers.dylib`__asan_get_alloc_stack
1 match found in /Users/michaelbuch/Git/lldb-build-main-no-modules/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:
        Address: libclang_rt.asan_osx_dynamic.dylib[0x0000000000009ec0] (libclang_rt.asan_osx_dynamic.dylib.__TEXT.__text + 34352)
        Summary: libclang_rt.asan_osx_dynamic.dylib`::__asan_get_alloc_stack(__sanitizer::uptr, __sanitizer::uptr *, __sanitizer::uptr, __sanitizer::u32 *) at asan_debugging.cpp:132
(lldb) memory history 'pointer'
Assertion failed: ((uintptr_t)addr == report.access.address), function __asan_get_alloc_stack, file debugger_abi.cpp, line 62.
warning: cannot evaluate AddressSanitizer expression:
error: Expression execution was interrupted: signal SIGABRT.
The process has been returned to the state before expression evaluation.
```

The reason for this is that the system sanitizer dylib and the locally
built libclang_rt contain the same symbol `__asan_get_alloc_stack`, and
depending on the order in which they're loaded, we may pick the one from
the wrong dylib (this probably changed during the buildbot upgrade and
is why it only now started failing). Based on discussion with @wrotki we
always want to pick the one that's in the libclang_rt dylib if it was
loaded, and libsystem_sanitizers otherwise.

This patch addresses this by adding a "preferred lookup context list" to
the expression evaluator. Currently this is only exposed in the
`EvaluateExpressionOptions`. We make it a `SymbolContextList` in case we
want the lookup contexts to be contexts other than modules (e.g., source
files, etc.). In `IRExecutionUnit` we make it a `ModuleList` because it
makes the symbol lookup implementation simpler and we only do module
lookups here anyway. If we ever need it to be a `SymbolContext`, that
transformation shouldn't be too difficult.

(cherry picked from commit 542d52b)
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.

4 participants