[Lldb-commits] [lldb] [lldb] Store the dummy target in the selected execution context (PR #190496)

via lldb-commits lldb-commits at lists.llvm.org
Sat Apr 4 18:03:54 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

<details>
<summary>Changes</summary>

Store the dummy target in the selected execution context. There's no reason for everybody to have to independently fall back to the dummy target.

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


7 Files Affected:

- (modified) lldb/include/lldb/Core/Debugger.h (+2-4) 
- (modified) lldb/source/Commands/CommandObjectDWIMPrint.cpp (+2-4) 
- (modified) lldb/source/Core/Debugger.cpp (+1-3) 
- (modified) lldb/source/Interpreter/CommandInterpreter.cpp (+1-5) 
- (modified) lldb/source/Interpreter/CommandObject.cpp (+14-16) 
- (modified) lldb/source/Target/Target.cpp (+1-1) 
- (modified) lldb/unittests/Core/DebuggerTest.cpp (+22) 


``````````diff
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index fa4483c93e639..23fc34d29b8d7 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -208,12 +208,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
   }
 
   /// Get the execution context representing the selected entities in the
-  /// selected target.
+  /// selected target, or the dummy target if no target is selected.
   ExecutionContext GetSelectedExecutionContext();
 
-  /// Similar to GetSelectedExecutionContext but returns a
-  /// ExecutionContextRef, and will hold the dummy target if no target is
-  /// currently selected.
+  /// Like GetSelectedExecutionContext but returns an ExecutionContextRef.
   ExecutionContextRef GetSelectedExecutionContextRef();
 
   /// Get accessor for the target list.
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 27bd71c21ad3f..ca9e9c72f1ba7 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -75,9 +75,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
 
   auto verbosity = GetDebugger().GetDWIMPrintVerbosity();
 
-  Target *target_ptr = m_exe_ctx.GetTargetPtr();
-  // Fallback to the dummy target, which can allow for expression evaluation.
-  Target &target = target_ptr ? *target_ptr : GetDummyTarget();
+  Target &target = m_exe_ctx.GetTargetRef();
 
   EvaluateExpressionOptions eval_options =
       m_expr_options.GetEvaluateExpressionOptions(target, m_varobj_options);
@@ -118,7 +116,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
     static const std::regex swift_class_regex(
         "^<\\S+: 0x[[:xdigit:]]{5,}>\\s*$");
 
-    if (GetDebugger().GetShowDontUsePoHint() && target_ptr &&
+    if (GetDebugger().GetShowDontUsePoHint() && !target.IsDummyTarget() &&
         (language.AsLanguageType() == lldb::eLanguageTypeSwift ||
          language.IsObjC()) &&
         std::regex_match(output.data(), swift_class_regex)) {
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index e1b2ce1b063e0..47a8603a5518e 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -1285,9 +1285,7 @@ void Debugger::RedrawStatusline(
 }
 
 ExecutionContext Debugger::GetSelectedExecutionContext() {
-  bool adopt_selected = true;
-  ExecutionContextRef exe_ctx_ref(GetSelectedTarget().get(), adopt_selected);
-  return ExecutionContext(exe_ctx_ref);
+  return ExecutionContext(GetSelectedExecutionContextRef());
 }
 
 ExecutionContextRef Debugger::GetSelectedExecutionContextRef() {
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index eeb1ae0ff3eb8..dba1f91c1a561 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -1972,11 +1972,7 @@ Status CommandInterpreter::PreprocessToken(std::string &expr_str) {
   Status error;
   ExecutionContext exe_ctx(GetExecutionContext());
 
-  // Get a dummy target to allow for calculator mode while processing
-  // backticks. This also helps break the infinite loop caused when target is
-  // null.
-  Target *exe_target = exe_ctx.GetTargetPtr();
-  Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
+  Target &target = exe_ctx.GetTargetRef();
 
   ValueObjectSP expr_result_valobj_sp;
 
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
index 38a34496e73ff..3b3b2d7a302d9 100644
--- a/lldb/source/Interpreter/CommandObject.cpp
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -147,7 +147,12 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
   // we don't want any CommandObject instances to keep any of these objects
   // around longer than for a single command. Every command should call
   // CommandObject::Cleanup() after it has completed.
-  assert(!m_exe_ctx.GetTargetPtr());
+  //
+  // The dummy target is allowed here because it is always alive, never causes
+  // resource leaks, and can appear when a command (e.g. "command source") is
+  // invoked re-entrantly before the outer Cleanup() has run.
+  assert(!m_exe_ctx.GetTargetPtr() ||
+         m_exe_ctx.GetTargetPtr()->IsDummyTarget());
   assert(!m_exe_ctx.GetProcessPtr());
   assert(!m_exe_ctx.GetThreadPtr());
   assert(!m_exe_ctx.GetFramePtr());
@@ -162,13 +167,15 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
                eCommandRequiresThread | eCommandRequiresFrame |
                eCommandTryTargetAPILock)) {
 
-    if ((flags & eCommandRequiresTarget) && !m_exe_ctx.HasTargetScope()) {
+    Target *target = m_exe_ctx.GetTargetPtr();
+    if ((flags & eCommandRequiresTarget) &&
+        (!target || target->IsDummyTarget())) {
       result.AppendError(GetInvalidTargetDescription());
       return false;
     }
 
     if ((flags & eCommandRequiresProcess) && !m_exe_ctx.HasProcessScope()) {
-      if (!m_exe_ctx.HasTargetScope())
+      if (!target || target->IsDummyTarget())
         result.AppendError(GetInvalidTargetDescription());
       else
         result.AppendError(GetInvalidProcessDescription());
@@ -176,7 +183,7 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
     }
 
     if ((flags & eCommandRequiresThread) && !m_exe_ctx.HasThreadScope()) {
-      if (!m_exe_ctx.HasTargetScope())
+      if (!target || target->IsDummyTarget())
         result.AppendError(GetInvalidTargetDescription());
       else if (!m_exe_ctx.HasProcessScope())
         result.AppendError(GetInvalidProcessDescription());
@@ -186,7 +193,7 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
     }
 
     if ((flags & eCommandRequiresFrame) && !m_exe_ctx.HasFrameScope()) {
-      if (!m_exe_ctx.HasTargetScope())
+      if (!target || target->IsDummyTarget())
         result.AppendError(GetInvalidTargetDescription());
       else if (!m_exe_ctx.HasProcessScope())
         result.AppendError(GetInvalidProcessDescription());
@@ -204,8 +211,7 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
     }
 
     if (flags & eCommandTryTargetAPILock) {
-      Target *target = m_exe_ctx.GetTargetPtr();
-      if (target)
+      if (target && !target->IsDummyTarget())
         m_api_locker =
             std::unique_lock<std::recursive_mutex>(target->GetAPIMutex());
     }
@@ -761,15 +767,7 @@ Target &CommandObject::GetTarget() {
   // Fallback to the command interpreter's execution context in case we get
   // called after DoExecute has finished. For example, when doing multi-line
   // expression that uses an input reader or breakpoint callbacks.
-  if (Target *target = m_interpreter.GetExecutionContext().GetTargetPtr())
-    return *target;
-
-  // Finally, if we have no other target, get the selected target.
-  if (TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget())
-    return *target_sp;
-
-  // We only have the dummy target.
-  return GetDummyTarget();
+  return m_interpreter.GetExecutionContext().GetTargetRef();
 }
 
 Thread *CommandObject::GetDefaultThread() {
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 0168c7d686e37..538cd6b3a6e7c 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -4440,7 +4440,7 @@ class TargetOptionValueProperties
     // we just use the one from this instance.
     if (exe_ctx) {
       Target *target = exe_ctx->GetTargetPtr();
-      if (target) {
+      if (target && !target->IsDummyTarget()) {
         TargetOptionValueProperties *target_properties =
             static_cast<TargetOptionValueProperties *>(
                 target->GetValueProperties().get());
diff --git a/lldb/unittests/Core/DebuggerTest.cpp b/lldb/unittests/Core/DebuggerTest.cpp
index 4dccd912c63ae..0897f682c7aa6 100644
--- a/lldb/unittests/Core/DebuggerTest.cpp
+++ b/lldb/unittests/Core/DebuggerTest.cpp
@@ -12,6 +12,7 @@
 #include "TestingSupport/TestUtilities.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/HostInfo.h"
+#include "lldb/Target/ExecutionContext.h"
 #include "gtest/gtest.h"
 
 using namespace lldb;
@@ -50,3 +51,24 @@ TEST_F(DebuggerTest, TestSettings) {
 
   Debugger::Destroy(debugger_sp);
 }
+
+TEST_F(DebuggerTest,
+       SelectedExecutionContextUsesDummyTargetWhenNoTargetSelected) {
+  DebuggerSP debugger_sp = Debugger::CreateInstance();
+
+  // No targets have been added, so no target is selected.
+  ASSERT_EQ(debugger_sp->GetSelectedTarget().get(), nullptr);
+
+  Target &dummy_target = debugger_sp->GetDummyTarget();
+
+  // GetSelectedExecutionContextRef should fall back to the dummy target.
+  ExecutionContextRef exe_ctx_ref =
+      debugger_sp->GetSelectedExecutionContextRef();
+  EXPECT_EQ(exe_ctx_ref.GetTargetSP().get(), &dummy_target);
+
+  // GetSelectedExecutionContext should also contain the dummy target.
+  ExecutionContext exe_ctx = debugger_sp->GetSelectedExecutionContext();
+  EXPECT_EQ(exe_ctx.GetTargetPtr(), &dummy_target);
+
+  Debugger::Destroy(debugger_sp);
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/190496


More information about the lldb-commits mailing list