[Lldb-commits] [lldb] [lldb] Limit DIL globals to only current file (PR #192592)

Dave Lee via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 17 09:20:24 PDT 2026


https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/192592

>From 3c5f71d6c496dfb48b15067a314f6ba2f0817c9f Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 16 Apr 2026 21:39:51 -0700
Subject: [PATCH 1/4] [lldb] Limit DIL globals to only current file

DIL has supported unlimited global lookup, which is in contrast with legacy
`frame variable` behavior, which supports only globals in the current file.

This is semantically incorrect for `frame variable`, and has shown to produce
bugs in `dwim-print`. For these reasons, this change proposes limiting DIL
globals to only globals from the current compilation unit.

For `dwim-print`, the bug manifests as when a global shadows a computed
property of the instance variable (`self`). As an example, if a global named
`text` exists, and a property named `text` exists (ie `self.text`), then
running `dwim-print text` will unexpectedly print the global, not `self.text`.

Assisted-by: claude
---
 lldb/include/lldb/ValueObject/DILEval.h       |  7 +++---
 lldb/source/ValueObject/DILEval.cpp           | 25 +++----------------
 lldb/source/ValueObject/DILParser.cpp         |  3 +--
 .../TestFrameVarDILGlobalVariableLookup.py    | 23 ++++++++++++-----
 4 files changed, 24 insertions(+), 34 deletions(-)

diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index c5f41b5a0bc76..ec495b4ea9061 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -28,12 +28,11 @@ lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,
                                      lldb::DynamicValueType use_dynamic);
 
 /// Given the name of an identifier, check to see if it matches the name of a
-/// global variable. If so, find the ValueObject for that global variable, and
-/// create and return an IdentifierInfo object containing all the relevant
-/// informatin about it.
+/// global variable in the current compile unit. If so, find the ValueObject for
+/// that global variable, and create and return an IdentifierInfo object
+/// containing all the relevant information about it.
 lldb::ValueObjectSP LookupGlobalIdentifier(llvm::StringRef name_ref,
                                            std::shared_ptr<StackFrame> frame_sp,
-                                           lldb::TargetSP target_sp,
                                            lldb::DynamicValueType use_dynamic);
 
 class Interpreter : Visitor {
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 7801b9225f19e..228524b00256d 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -16,7 +16,6 @@
 #include "lldb/ValueObject/DILParser.h"
 #include "lldb/ValueObject/ValueObject.h"
 #include "lldb/ValueObject/ValueObjectRegister.h"
-#include "lldb/ValueObject/ValueObjectVariable.h"
 #include "llvm/Support/FormatAdapters.h"
 #include <memory>
 
@@ -293,7 +292,7 @@ static lldb::VariableSP DILFindVariable(ConstString name,
 
 lldb::ValueObjectSP LookupGlobalIdentifier(
     llvm::StringRef name_ref, std::shared_ptr<StackFrame> stack_frame,
-    lldb::TargetSP target_sp, lldb::DynamicValueType use_dynamic) {
+    lldb::DynamicValueType use_dynamic) {
   // Get a global variables list without the locals from the current frame
   SymbolContext symbol_context =
       stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit);
@@ -311,25 +310,7 @@ lldb::ValueObjectSP LookupGlobalIdentifier(
           stack_frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);
   }
 
-  if (value_sp)
-    return value_sp;
-
-  // Check for match in modules global variables.
-  VariableList modules_var_list;
-  target_sp->GetImages().FindGlobalVariables(
-      ConstString(name_ref), std::numeric_limits<uint32_t>::max(),
-      modules_var_list);
-
-  if (!modules_var_list.Empty()) {
-    lldb::VariableSP var_sp =
-        DILFindVariable(ConstString(name_ref), modules_var_list);
-    if (var_sp)
-      value_sp = ValueObjectVariable::Create(stack_frame.get(), var_sp);
-
-    if (value_sp)
-      return value_sp;
-  }
-  return nullptr;
+  return value_sp;
 }
 
 lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,
@@ -438,7 +419,7 @@ Interpreter::Visit(const IdentifierNode &node) {
 
   if (!identifier)
     identifier = LookupGlobalIdentifier(node.GetName(), m_exe_ctx_scope,
-                                        m_target, use_dynamic);
+                                        use_dynamic);
   if (!identifier) {
     std::string errMsg =
         llvm::formatv("use of undeclared identifier '{0}'", node.GetName());
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 51bdffd5087ca..9fb7206429555 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -479,8 +479,7 @@ std::optional<CompilerType> DILParser::ParseTypeId() {
       return {};
 
     // Same-name identifiers should be preferred over typenames.
-    if (LookupGlobalIdentifier(type_name, m_ctx_scope,
-                               m_ctx_scope->CalculateTarget(), m_use_dynamic))
+    if (LookupGlobalIdentifier(type_name, m_ctx_scope, m_use_dynamic))
       // TODO: Make type accessible with 'class', 'struct' and 'union' keywords
       return {};
   }
diff --git a/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
index 5c91755ed0db6..0a59e565d976f 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
@@ -49,12 +49,23 @@ def test_frame_var(self):
         self.expect_var_path("::ns::globalPtr", type="int *")
         self.expect_var_path("::ns::globalRef", type="int &")
 
-        self.expect_var_path("externGlobalVar", value="2")
-        self.expect_var_path("::externGlobalVar", value="2")
-        self.expect_var_path("ext::externGlobalVar", value="4")
-        self.expect_var_path("::ext::externGlobalVar", value="4")
-
-        self.expect_var_path("ExtStruct::static_inline", value="16")
+        # Globals from other compile units are not accessible (matching legacy
+        # frame var behavior).
+        self.expect(
+            "frame var externGlobalVar",
+            error=True,
+            substrs=["use of undeclared identifier"],
+        )
+        self.expect(
+            "frame var ext::externGlobalVar",
+            error=True,
+            substrs=["use of undeclared identifier"],
+        )
+        self.expect(
+            "frame var ExtStruct::static_inline",
+            error=True,
+            substrs=["use of undeclared identifier"],
+        )
 
         # Test local variable priority over global
         self.expect_var_path("foo", value="1")

>From cb0530781fbcf43cc552e760a51f237bbbb08758 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 16 Apr 2026 21:52:13 -0700
Subject: [PATCH 2/4] formatting

---
 lldb/source/ValueObject/DILEval.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 228524b00256d..0abe403f6c120 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -290,9 +290,10 @@ static lldb::VariableSP DILFindVariable(ConstString name,
   return nullptr;
 }
 
-lldb::ValueObjectSP LookupGlobalIdentifier(
-    llvm::StringRef name_ref, std::shared_ptr<StackFrame> stack_frame,
-    lldb::DynamicValueType use_dynamic) {
+lldb::ValueObjectSP
+LookupGlobalIdentifier(llvm::StringRef name_ref,
+                       std::shared_ptr<StackFrame> stack_frame,
+                       lldb::DynamicValueType use_dynamic) {
   // Get a global variables list without the locals from the current frame
   SymbolContext symbol_context =
       stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit);
@@ -418,8 +419,8 @@ Interpreter::Visit(const IdentifierNode &node) {
       LookupIdentifier(node.GetName(), m_exe_ctx_scope, use_dynamic);
 
   if (!identifier)
-    identifier = LookupGlobalIdentifier(node.GetName(), m_exe_ctx_scope,
-                                        use_dynamic);
+    identifier =
+        LookupGlobalIdentifier(node.GetName(), m_exe_ctx_scope, use_dynamic);
   if (!identifier) {
     std::string errMsg =
         llvm::formatv("use of undeclared identifier '{0}'", node.GetName());

>From 257c009ed28b1b1a238f76b1c8f82cd0aa048f2a Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Fri, 17 Apr 2026 09:10:03 -0700
Subject: [PATCH 3/4] Put global variable lookup behind new flag

---
 lldb/include/lldb/Target/StackFrame.h   |  3 +-
 lldb/include/lldb/ValueObject/DILEval.h | 12 +++++---
 lldb/source/ValueObject/DILEval.cpp     | 40 ++++++++++++++++++++-----
 lldb/source/ValueObject/DILParser.cpp   |  3 +-
 4 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
index 66a7cec5f66b1..bcf0e55b0e3c1 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -57,7 +57,8 @@ class StackFrame : public ExecutionContextScope,
     eExpressionPathOptionsNoSyntheticArrayRange = (1u << 3),
     eExpressionPathOptionsAllowDirectIVarAccess = (1u << 4),
     eExpressionPathOptionsInspectAnonymousUnions = (1u << 5),
-    eExpressionPathOptionsAllowVarUpdates = (1u << 6)
+    eExpressionPathOptionsAllowVarUpdates = (1u << 6),
+    eExpressionPathOptionsAllowAllGlobals = (1u << 7)
   };
 
   enum class Kind {
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index ec495b4ea9061..6c9f2cdc86e16 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -28,12 +28,15 @@ lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,
                                      lldb::DynamicValueType use_dynamic);
 
 /// Given the name of an identifier, check to see if it matches the name of a
-/// global variable in the current compile unit. If so, find the ValueObject for
-/// that global variable, and create and return an IdentifierInfo object
-/// containing all the relevant information about it.
+/// global variable. If so, find the ValueObject for that global variable, and
+/// create and return an IdentifierInfo object containing all the relevant
+/// information about it. If \p search_all_modules is true, also search global
+/// variables from all loaded modules (not just the current compile unit).
 lldb::ValueObjectSP LookupGlobalIdentifier(llvm::StringRef name_ref,
                                            std::shared_ptr<StackFrame> frame_sp,
-                                           lldb::DynamicValueType use_dynamic);
+                                           lldb::TargetSP target_sp,
+                                           lldb::DynamicValueType use_dynamic,
+                                           bool search_all_modules = false);
 
 class Interpreter : Visitor {
 public:
@@ -146,6 +149,7 @@ class Interpreter : Visitor {
   bool m_check_ptr_vs_member;
   // TODO: Remove 'maybe_unused' when next PR, using this, gets submitted.
   [[maybe_unused]] bool m_allow_var_updates;
+  bool m_allow_all_globals;
 };
 
 } // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 0abe403f6c120..5de67f3881b67 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -16,6 +16,7 @@
 #include "lldb/ValueObject/DILParser.h"
 #include "lldb/ValueObject/ValueObject.h"
 #include "lldb/ValueObject/ValueObjectRegister.h"
+#include "lldb/ValueObject/ValueObjectVariable.h"
 #include "llvm/Support/FormatAdapters.h"
 #include <memory>
 
@@ -290,10 +291,10 @@ static lldb::VariableSP DILFindVariable(ConstString name,
   return nullptr;
 }
 
-lldb::ValueObjectSP
-LookupGlobalIdentifier(llvm::StringRef name_ref,
-                       std::shared_ptr<StackFrame> stack_frame,
-                       lldb::DynamicValueType use_dynamic) {
+lldb::ValueObjectSP LookupGlobalIdentifier(
+    llvm::StringRef name_ref, std::shared_ptr<StackFrame> stack_frame,
+    lldb::TargetSP target_sp, lldb::DynamicValueType use_dynamic,
+    bool search_all_modules) {
   // Get a global variables list without the locals from the current frame
   SymbolContext symbol_context =
       stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit);
@@ -311,7 +312,28 @@ LookupGlobalIdentifier(llvm::StringRef name_ref,
           stack_frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);
   }
 
-  return value_sp;
+  if (value_sp)
+    return value_sp;
+
+  if (!search_all_modules)
+    return nullptr;
+
+  // Check for match in modules global variables.
+  VariableList modules_var_list;
+  target_sp->GetImages().FindGlobalVariables(
+      ConstString(name_ref), std::numeric_limits<uint32_t>::max(),
+      modules_var_list);
+
+  if (!modules_var_list.Empty()) {
+    lldb::VariableSP var_sp =
+        DILFindVariable(ConstString(name_ref), modules_var_list);
+    if (var_sp)
+      value_sp = ValueObjectVariable::Create(stack_frame.get(), var_sp);
+
+    if (value_sp)
+      return value_sp;
+  }
+  return nullptr;
 }
 
 lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,
@@ -376,11 +398,14 @@ Interpreter::Interpreter(lldb::TargetSP target, llvm::StringRef expr,
       (options & StackFrame::eExpressionPathOptionsNoSyntheticChildren) != 0;
   const bool allow_var_updates =
       (options & StackFrame::eExpressionPathOptionsAllowVarUpdates) != 0;
+  const bool allow_all_globals =
+      (options & StackFrame::eExpressionPathOptionsAllowAllGlobals) != 0;
 
   m_use_synthetic = !no_synth_child;
   m_fragile_ivar = !no_fragile_ivar;
   m_check_ptr_vs_member = check_ptr_vs_member;
   m_allow_var_updates = allow_var_updates;
+  m_allow_all_globals = allow_all_globals;
 }
 
 llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode &node) {
@@ -419,8 +444,9 @@ Interpreter::Visit(const IdentifierNode &node) {
       LookupIdentifier(node.GetName(), m_exe_ctx_scope, use_dynamic);
 
   if (!identifier)
-    identifier =
-        LookupGlobalIdentifier(node.GetName(), m_exe_ctx_scope, use_dynamic);
+    identifier = LookupGlobalIdentifier(node.GetName(), m_exe_ctx_scope,
+                                        m_target, use_dynamic,
+                                        m_allow_all_globals);
   if (!identifier) {
     std::string errMsg =
         llvm::formatv("use of undeclared identifier '{0}'", node.GetName());
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 9fb7206429555..51bdffd5087ca 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -479,7 +479,8 @@ std::optional<CompilerType> DILParser::ParseTypeId() {
       return {};
 
     // Same-name identifiers should be preferred over typenames.
-    if (LookupGlobalIdentifier(type_name, m_ctx_scope, m_use_dynamic))
+    if (LookupGlobalIdentifier(type_name, m_ctx_scope,
+                               m_ctx_scope->CalculateTarget(), m_use_dynamic))
       // TODO: Make type accessible with 'class', 'struct' and 'union' keywords
       return {};
   }

>From 1bf20ff4de2f5b3acaf061cbc8a0c0c5ebe4adb5 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Fri, 17 Apr 2026 09:18:15 -0700
Subject: [PATCH 4/4] Allow global lookup in SBFrame::GetValueForVariablePath

---
 lldb/source/API/SBFrame.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index c0f932cc2c43b..83199a1f95c20 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -406,7 +406,8 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
     ValueObjectSP value_sp(frame->GetValueForVariableExpressionPath(
         var_path, eNoDynamicValues,
         StackFrame::eExpressionPathOptionCheckPtrVsMember |
-            StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
+            StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
+            StackFrame::eExpressionPathOptionsAllowAllGlobals,
         var_sp, error, mode));
     sb_value.SetSP(value_sp, use_dynamic);
   }



More information about the lldb-commits mailing list