Reland "[lldb] Make CommandInterpreter's execution context the same as debugger's one"

GitOrigin-RevId: 36de94cf54efbad967a9a0fa41329a8b59bc35c4
diff --git a/include/lldb/Interpreter/CommandInterpreter.h b/include/lldb/Interpreter/CommandInterpreter.h
index c4f9dd2..7f897bf 100644
--- a/include/lldb/Interpreter/CommandInterpreter.h
+++ b/include/lldb/Interpreter/CommandInterpreter.h
@@ -24,7 +24,9 @@
 #include "lldb/Utility/StringList.h"
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-private.h"
+
 #include <mutex>
+#include <stack>
 
 namespace lldb_private {
 class CommandInterpreter;
@@ -245,7 +247,7 @@
 
   CommandInterpreter(Debugger &debugger, bool synchronous_execution);
 
-  ~CommandInterpreter() override;
+  ~CommandInterpreter() override = default;
 
   // These two functions fill out the Broadcaster interface:
 
@@ -300,10 +302,11 @@
                                   CommandReturnObject &result);
 
   bool HandleCommand(const char *command_line, LazyBool add_to_history,
-                     CommandReturnObject &result,
-                     ExecutionContext *override_context = nullptr,
-                     bool repeat_on_empty_command = true,
-                     bool no_context_switching = false);
+                     const ExecutionContext &override_context,
+                     CommandReturnObject &result);
+
+  bool HandleCommand(const char *command_line, LazyBool add_to_history,
+                     CommandReturnObject &result);
 
   bool WasInterrupted() const;
 
@@ -312,9 +315,7 @@
   /// \param[in] commands
   ///    The list of commands to execute.
   /// \param[in,out] context
-  ///    The execution context in which to run the commands. Can be nullptr in
-  ///    which case the default
-  ///    context will be used.
+  ///    The execution context in which to run the commands.
   /// \param[in] options
   ///    This object holds the options used to control when to stop, whether to
   ///    execute commands,
@@ -324,8 +325,13 @@
   ///    safely,
   ///    and failed with some explanation if we aborted executing the commands
   ///    at some point.
-  void HandleCommands(const StringList &commands, ExecutionContext *context,
-                      CommandInterpreterRunOptions &options,
+  void HandleCommands(const StringList &commands,
+                      const ExecutionContext &context,
+                      const CommandInterpreterRunOptions &options,
+                      CommandReturnObject &result);
+
+  void HandleCommands(const StringList &commands,
+                      const CommandInterpreterRunOptions &options,
                       CommandReturnObject &result);
 
   /// Execute a list of commands from a file.
@@ -333,9 +339,7 @@
   /// \param[in] file
   ///    The file from which to read in commands.
   /// \param[in,out] context
-  ///    The execution context in which to run the commands. Can be nullptr in
-  ///    which case the default
-  ///    context will be used.
+  ///    The execution context in which to run the commands.
   /// \param[in] options
   ///    This object holds the options used to control when to stop, whether to
   ///    execute commands,
@@ -345,8 +349,12 @@
   ///    safely,
   ///    and failed with some explanation if we aborted executing the commands
   ///    at some point.
-  void HandleCommandsFromFile(FileSpec &file, ExecutionContext *context,
-                              CommandInterpreterRunOptions &options,
+  void HandleCommandsFromFile(FileSpec &file, const ExecutionContext &context,
+                              const CommandInterpreterRunOptions &options,
+                              CommandReturnObject &result);
+
+  void HandleCommandsFromFile(FileSpec &file,
+                              const CommandInterpreterRunOptions &options,
                               CommandReturnObject &result);
 
   CommandObject *GetCommandObjectForCommand(llvm::StringRef &command_line);
@@ -391,12 +399,7 @@
 
   Debugger &GetDebugger() { return m_debugger; }
 
-  ExecutionContext GetExecutionContext() {
-    const bool thread_and_frame_only_if_stopped = true;
-    return m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped);
-  }
-
-  void UpdateExecutionContext(ExecutionContext *override_context);
+  ExecutionContext GetExecutionContext() const;
 
   lldb::PlatformSP GetPlatform(bool prefer_target_platform);
 
@@ -581,6 +584,10 @@
                                      StringList *descriptions = nullptr) const;
 
 private:
+  void OverrideExecutionContext(const ExecutionContext &override_context);
+
+  void RestoreExecutionContext();
+
   Status PreprocessCommand(std::string &command);
 
   void SourceInitFile(FileSpec file, CommandReturnObject &result);
@@ -619,8 +626,9 @@
 
   Debugger &m_debugger; // The debugger session that this interpreter is
                         // associated with
-  ExecutionContextRef m_exe_ctx_ref; // The current execution context to use
-                                     // when handling commands
+  // Execution contexts that were temporarily set by some of HandleCommand*
+  // overloads.
+  std::stack<ExecutionContext> m_overriden_exe_contexts;
   bool m_synchronous_execution;
   bool m_skip_lldbinit_files;
   bool m_skip_app_init_files;
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
index 31e7da8..d28bc41 100644
--- a/source/API/SBCommandInterpreter.cpp
+++ b/source/API/SBCommandInterpreter.cpp
@@ -171,27 +171,23 @@
                       lldb::SBCommandReturnObject &, bool),
                      command_line, override_context, result, add_to_history);
 
-
-  ExecutionContext ctx, *ctx_ptr;
-  if (override_context.get()) {
-    ctx = override_context.get()->Lock(true);
-    ctx_ptr = &ctx;
-  } else
-    ctx_ptr = nullptr;
-
   result.Clear();
   if (command_line && IsValid()) {
     result.ref().SetInteractive(false);
-    m_opaque_ptr->HandleCommand(command_line,
-                                add_to_history ? eLazyBoolYes : eLazyBoolNo,
-                                result.ref(), ctx_ptr);
+    auto do_add_to_history = add_to_history ? eLazyBoolYes : eLazyBoolNo;
+    if (override_context.get())
+      m_opaque_ptr->HandleCommand(command_line, do_add_to_history,
+                                  override_context.get()->Lock(true),
+                                  result.ref());
+    else
+      m_opaque_ptr->HandleCommand(command_line, do_add_to_history,
+                                  result.ref());
   } else {
     result->AppendError(
         "SBCommandInterpreter or the command line is not valid");
     result->SetStatus(eReturnStatusFailed);
   }
 
-
   return result.GetStatus();
 }
 
@@ -219,15 +215,14 @@
   }
 
   FileSpec tmp_spec = file.ref();
-  ExecutionContext ctx, *ctx_ptr;
-  if (override_context.get()) {
-    ctx = override_context.get()->Lock(true);
-    ctx_ptr = &ctx;
-  } else
-    ctx_ptr = nullptr;
+  if (override_context.get())
+    m_opaque_ptr->HandleCommandsFromFile(tmp_spec,
+                                         override_context.get()->Lock(true),
+                                         options.ref(),
+                                         result.ref());
 
-  m_opaque_ptr->HandleCommandsFromFile(tmp_spec, ctx_ptr, options.ref(),
-                                       result.ref());
+  else
+    m_opaque_ptr->HandleCommandsFromFile(tmp_spec, options.ref(), result.ref());
 }
 
 int SBCommandInterpreter::HandleCompletion(
diff --git a/source/Breakpoint/BreakpointOptions.cpp b/source/Breakpoint/BreakpointOptions.cpp
index f6bb763..2fdb53e 100644
--- a/source/Breakpoint/BreakpointOptions.cpp
+++ b/source/Breakpoint/BreakpointOptions.cpp
@@ -649,7 +649,7 @@
       options.SetPrintErrors(true);
       options.SetAddToHistory(false);
 
-      debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
+      debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx,
                                                       options, result);
       result.GetImmediateOutputStream()->Flush();
       result.GetImmediateErrorStream()->Flush();
diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp
index 3b3cdde..74b16a6 100644
--- a/source/Commands/CommandObjectCommands.cpp
+++ b/source/Commands/CommandObjectCommands.cpp
@@ -134,15 +134,12 @@
 
     FileSpec cmd_file(command[0].ref());
     FileSystem::Instance().Resolve(cmd_file);
-    ExecutionContext *exe_ctx = nullptr; // Just use the default context.
 
+    CommandInterpreterRunOptions options;
     // If any options were set, then use them
     if (m_options.m_stop_on_error.OptionWasSet() ||
         m_options.m_silent_run.OptionWasSet() ||
         m_options.m_stop_on_continue.OptionWasSet()) {
-      // Use user set settings
-      CommandInterpreterRunOptions options;
-
       if (m_options.m_stop_on_continue.OptionWasSet())
         options.SetStopOnContinue(
             m_options.m_stop_on_continue.GetCurrentValue());
@@ -159,14 +156,9 @@
         options.SetEchoCommands(m_interpreter.GetEchoCommands());
         options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
       }
-
-      m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result);
-    } else {
-      // No options were set, inherit any settings from nested "command source"
-      // commands, or set to sane default settings...
-      CommandInterpreterRunOptions options;
-      m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result);
     }
+
+    m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
     return result.Succeeded();
   }
 
diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp
index 58eaa3f..c7866f9 100644
--- a/source/Commands/CommandObjectExpression.cpp
+++ b/source/Commands/CommandObjectExpression.cpp
@@ -292,18 +292,12 @@
   options.SetAutoApplyFixIts(false);
   options.SetGenerateDebugInfo(false);
 
-  // We need a valid execution context with a frame pointer for this
-  // completion, so if we don't have one we should try to make a valid
-  // execution context.
-  if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr)
-    m_interpreter.UpdateExecutionContext(nullptr);
+  ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
 
-  // This didn't work, so let's get out before we start doing things that
-  // expect a valid frame pointer.
-  if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr)
+  // Get out before we start doing things that expect a valid frame pointer.
+  if (exe_ctx.GetFramePtr() == nullptr)
     return;
 
-  ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
   Target *exe_target = exe_ctx.GetTargetPtr();
   Target &target = exe_target ? *exe_target : GetDummyTarget();
 
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index 35835f6..c21c499 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -381,7 +381,6 @@
       return false;
     }
 
-    m_interpreter.UpdateExecutionContext(nullptr);
     StreamString stream;
     const auto error = target->Attach(m_options.attach_info, &stream);
     if (error.Success()) {
diff --git a/source/Commands/CommandObjectRegexCommand.cpp b/source/Commands/CommandObjectRegexCommand.cpp
index 1bf29d3..dcd05a1 100644
--- a/source/Commands/CommandObjectRegexCommand.cpp
+++ b/source/Commands/CommandObjectRegexCommand.cpp
@@ -53,8 +53,8 @@
       // Pass in true for "no context switching".  The command that called us
       // should have set up the context appropriately, we shouldn't have to
       // redo that.
-      return m_interpreter.HandleCommand(
-          new_command.c_str(), eLazyBoolCalculate, result, nullptr, true, true);
+      return m_interpreter.HandleCommand(new_command.c_str(),
+                                         eLazyBoolCalculate, result);
     }
   }
   result.SetStatus(eReturnStatusFailed);
diff --git a/source/Commands/CommandObjectSettings.cpp b/source/Commands/CommandObjectSettings.cpp
index 87e0352..d869377 100644
--- a/source/Commands/CommandObjectSettings.cpp
+++ b/source/Commands/CommandObjectSettings.cpp
@@ -469,14 +469,13 @@
   bool DoExecute(Args &command, CommandReturnObject &result) override {
     FileSpec file(m_options.m_filename);
     FileSystem::Instance().Resolve(file);
-    ExecutionContext clean_ctx;
     CommandInterpreterRunOptions options;
     options.SetAddToHistory(false);
     options.SetEchoCommands(false);
     options.SetPrintResults(true);
     options.SetPrintErrors(true);
     options.SetStopOnError(false);
-    m_interpreter.HandleCommandsFromFile(file, &clean_ctx, options, result);
+    m_interpreter.HandleCommandsFromFile(file, options, result);
     return result.Succeeded();
   }
 
diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp
index fe3052a..3df17a0 100644
--- a/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -301,7 +301,7 @@
         options.SetPrintErrors(true);
         options.SetAddToHistory(false);
 
-        debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
+        debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx,
                                                         options, result);
         result.GetImmediateOutputStream()->Flush();
         result.GetImmediateErrorStream()->Flush();
diff --git a/source/Core/IOHandlerCursesGUI.cpp b/source/Core/IOHandlerCursesGUI.cpp
index 19066e6..af9fb29 100644
--- a/source/Core/IOHandlerCursesGUI.cpp
+++ b/source/Core/IOHandlerCursesGUI.cpp
@@ -1390,8 +1390,6 @@
                 ConstString broadcaster_class(
                     broadcaster->GetBroadcasterClass());
                 if (broadcaster_class == broadcaster_class_process) {
-                  debugger.GetCommandInterpreter().UpdateExecutionContext(
-                      nullptr);
                   m_update_screen = true;
                   continue; // Don't get any key, just update our view
                 }
@@ -1403,7 +1401,6 @@
         HandleCharResult key_result = m_window_sp->HandleChar(ch);
         switch (key_result) {
         case eKeyHandled:
-          debugger.GetCommandInterpreter().UpdateExecutionContext(nullptr);
           m_update_screen = true;
           break;
         case eKeyNotHandled:
diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp
index fb503fe..0b25abc 100644
--- a/source/Interpreter/CommandInterpreter.cpp
+++ b/source/Interpreter/CommandInterpreter.cpp
@@ -76,6 +76,7 @@
 #include "lldb/Target/UnixSignals.h"
 
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/FormatAdapters.h"
 #include "llvm/Support/Path.h"
@@ -1631,12 +1632,18 @@
 
 bool CommandInterpreter::HandleCommand(const char *command_line,
                                        LazyBool lazy_add_to_history,
-                                       CommandReturnObject &result,
-                                       ExecutionContext *override_context,
-                                       bool repeat_on_empty_command,
-                                       bool no_context_switching)
+                                       const ExecutionContext &override_context,
+                                       CommandReturnObject &result) {
 
-{
+  OverrideExecutionContext(override_context);
+  bool status = HandleCommand(command_line, lazy_add_to_history, result);
+  RestoreExecutionContext();
+  return status;
+}
+
+bool CommandInterpreter::HandleCommand(const char *command_line,
+                                       LazyBool lazy_add_to_history,
+                                       CommandReturnObject &result) {
 
   std::string command_string(command_line);
   std::string original_command_string(command_line);
@@ -1648,9 +1655,6 @@
   LLDB_LOGF(log, "Processing command: %s", command_line);
   LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
 
-  if (!no_context_switching)
-    UpdateExecutionContext(override_context);
-
   if (WasInterrupted()) {
     result.AppendError("interrupted");
     result.SetStatus(eReturnStatusFailed);
@@ -1696,26 +1700,22 @@
   }
 
   if (empty_command) {
-    if (repeat_on_empty_command) {
-      if (m_command_history.IsEmpty()) {
-        result.AppendError("empty command");
-        result.SetStatus(eReturnStatusFailed);
-        return false;
-      } else {
-        command_line = m_repeat_command.c_str();
-        command_string = command_line;
-        original_command_string = command_line;
-        if (m_repeat_command.empty()) {
-          result.AppendError("No auto repeat.");
-          result.SetStatus(eReturnStatusFailed);
-          return false;
-        }
-      }
-      add_to_history = false;
-    } else {
-      result.SetStatus(eReturnStatusSuccessFinishNoResult);
-      return true;
+    if (m_command_history.IsEmpty()) {
+      result.AppendError("empty command");
+      result.SetStatus(eReturnStatusFailed);
+      return false;
     }
+
+    command_line = m_repeat_command.c_str();
+    command_string = command_line;
+    original_command_string = command_line;
+    if (m_repeat_command.empty()) {
+      result.AppendError("No auto repeat.");
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+
+    add_to_history = false;
   } else if (comment_command) {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
     return true;
@@ -1852,8 +1852,6 @@
 
 void CommandInterpreter::HandleCompletion(CompletionRequest &request) {
 
-  UpdateExecutionContext(nullptr);
-
   // Don't complete comments, and if the line we are completing is just the
   // history repeat character, substitute the appropriate history line.
   llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
@@ -1885,8 +1883,6 @@
   return llvm::None;
 }
 
-CommandInterpreter::~CommandInterpreter() {}
-
 void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
   EventSP prompt_change_event_sp(
       new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
@@ -2128,13 +2124,12 @@
   // broadcasting of the commands back to any appropriate listener (see
   // CommandObjectSource::Execute for more details).
   const bool saved_batch = SetBatchCommandMode(true);
-  ExecutionContext *ctx = nullptr;
   CommandInterpreterRunOptions options;
   options.SetSilent(true);
   options.SetPrintErrors(true);
   options.SetStopOnError(false);
   options.SetStopOnContinue(true);
-  HandleCommandsFromFile(file, ctx, options, result);
+  HandleCommandsFromFile(file, options, result);
   SetBatchCommandMode(saved_batch);
 }
 
@@ -2225,7 +2220,8 @@
 }
 
 bool CommandInterpreter::DidProcessStopAbnormally() const {
-  TargetSP target_sp = m_debugger.GetTargetList().GetSelectedTarget();
+  auto exe_ctx = GetExecutionContext();
+  TargetSP target_sp = exe_ctx.GetTargetSP();
   if (!target_sp)
     return false;
 
@@ -2263,9 +2259,19 @@
   return false;
 }
 
+void
+CommandInterpreter::HandleCommands(const StringList &commands,
+                                   const ExecutionContext &override_context,
+                                   const CommandInterpreterRunOptions &options,
+                                   CommandReturnObject &result) {
+
+  OverrideExecutionContext(override_context);
+  HandleCommands(commands, options, result);
+  RestoreExecutionContext();
+}
+
 void CommandInterpreter::HandleCommands(const StringList &commands,
-                                        ExecutionContext *override_context,
-                                        CommandInterpreterRunOptions &options,
+                                        const CommandInterpreterRunOptions &options,
                                         CommandReturnObject &result) {
   size_t num_lines = commands.GetSize();
 
@@ -2275,13 +2281,6 @@
 
   bool old_async_execution = m_debugger.GetAsyncExecution();
 
-  // If we've been given an execution context, set it at the start, but don't
-  // keep resetting it or we will cause series of commands that change the
-  // context, then do an operation that relies on that context to fail.
-
-  if (override_context != nullptr)
-    UpdateExecutionContext(override_context);
-
   if (!options.GetStopOnContinue()) {
     m_debugger.SetAsyncExecution(false);
   }
@@ -2300,19 +2299,12 @@
     CommandReturnObject tmp_result(m_debugger.GetUseColor());
     tmp_result.SetInteractive(result.GetInteractive());
 
-    // If override_context is not NULL, pass no_context_switching = true for
-    // HandleCommand() since we updated our context already.
-
     // We might call into a regex or alias command, in which case the
     // add_to_history will get lost.  This m_command_source_depth dingus is the
     // way we turn off adding to the history in that case, so set it up here.
     if (!options.GetAddToHistory())
       m_command_source_depth++;
-    bool success =
-        HandleCommand(cmd, options.m_add_to_history, tmp_result,
-                      nullptr, /* override_context */
-                      true,    /* repeat_on_empty_command */
-                      override_context != nullptr /* no_context_switching */);
+    bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
     if (!options.GetAddToHistory())
       m_command_source_depth--;
 
@@ -2413,8 +2405,15 @@
 };
 
 void CommandInterpreter::HandleCommandsFromFile(
-    FileSpec &cmd_file, ExecutionContext *context,
-    CommandInterpreterRunOptions &options, CommandReturnObject &result) {
+    FileSpec &cmd_file, const ExecutionContext &context,
+    const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
+  OverrideExecutionContext(context);
+  HandleCommandsFromFile(cmd_file, options, result);
+  RestoreExecutionContext();
+}
+
+void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
+    const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
   if (!FileSystem::Instance().Exists(cmd_file)) {
     result.AppendErrorWithFormat(
         "Error reading commands from file %s - file not found.\n",
@@ -2715,23 +2714,24 @@
                            m_alias_dict);
 }
 
-void CommandInterpreter::UpdateExecutionContext(
-    ExecutionContext *override_context) {
-  if (override_context != nullptr) {
-    m_exe_ctx_ref = *override_context;
-  } else {
-    const bool adopt_selected = true;
-    m_exe_ctx_ref.SetTargetPtr(m_debugger.GetSelectedTarget().get(),
-                               adopt_selected);
-  }
+ExecutionContext CommandInterpreter::GetExecutionContext() const {
+  return !m_overriden_exe_contexts.empty()
+             ? m_overriden_exe_contexts.top()
+             : m_debugger.GetSelectedExecutionContext();
+}
+
+void CommandInterpreter::OverrideExecutionContext(
+    const ExecutionContext &override_context) {
+  m_overriden_exe_contexts.push(override_context);
+}
+
+void CommandInterpreter::RestoreExecutionContext() {
+  if (!m_overriden_exe_contexts.empty())
+    m_overriden_exe_contexts.pop();
 }
 
 void CommandInterpreter::GetProcessOutput() {
-  TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
-  if (!target_sp)
-    return;
-
-  if (ProcessSP process_sp = target_sp->GetProcessSP())
+  if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
     m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
                                   /*flush_stderr*/ true);
 }
@@ -2831,6 +2831,9 @@
 
   StartHandlingCommand();
 
+  OverrideExecutionContext(m_debugger.GetSelectedExecutionContext());
+  llvm::make_scope_exit([this]() { RestoreExecutionContext(); });
+
   lldb_private::CommandReturnObject result(m_debugger.GetUseColor());
   HandleCommand(line.c_str(), eLazyBoolCalculate, result);
 
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index 736864e..da47d8e 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -3349,7 +3349,7 @@
   // Force Async:
   bool old_async = debugger.GetAsyncExecution();
   debugger.SetAsyncExecution(true);
-  debugger.GetCommandInterpreter().HandleCommands(GetCommands(), &exc_ctx,
+  debugger.GetCommandInterpreter().HandleCommands(GetCommands(), exc_ctx,
                                                   options, result);
   debugger.SetAsyncExecution(old_async);
   lldb::ReturnStatus status = result.GetStatus();
diff --git a/test/API/python_api/debugger/Makefile b/test/API/python_api/debugger/Makefile
new file mode 100644
index 0000000..bfad5f3
--- /dev/null
+++ b/test/API/python_api/debugger/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp

+

+include Makefile.rules

diff --git a/test/API/python_api/debugger/TestDebuggerAPI.py b/test/API/python_api/debugger/TestDebuggerAPI.py
index 32202ac..1559714 100644
--- a/test/API/python_api/debugger/TestDebuggerAPI.py
+++ b/test/API/python_api/debugger/TestDebuggerAPI.py
@@ -43,3 +43,54 @@
         target = lldb.SBTarget()
         self.assertFalse(target.IsValid())
         self.dbg.DeleteTarget(target)
+
+    def test_debugger_internal_variables(self):
+        """Ensure that SBDebugger reachs the same instance of properties
+           regardless CommandInterpreter's context initialization"""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+
+        # Create a target by the debugger.
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        property_name = "target.process.memory-cache-line-size"
+
+        def get_cache_line_size():
+            value_list = lldb.SBStringList()
+            value_list = self.dbg.GetInternalVariableValue(property_name,
+                                                           self.dbg.GetInstanceName())
+
+            self.assertEqual(value_list.GetSize(), 1)
+            try:
+                return int(value_list.GetStringAtIndex(0))
+            except ValueError as error:
+                self.fail("Value is not a number: " + error)
+
+        # Get global property value while there are no processes.
+        global_cache_line_size = get_cache_line_size()
+
+        # Run a process via SB interface. CommandInterpreter's execution context
+        # remains empty.
+        error = lldb.SBError()
+        launch_info = lldb.SBLaunchInfo(None)
+        launch_info.SetLaunchFlags(lldb.eLaunchFlagStopAtEntry)
+        process = target.Launch(launch_info, error)
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # This should change the value of a process's local property.
+        new_cache_line_size = global_cache_line_size + 512
+        error = self.dbg.SetInternalVariable(property_name,
+                                             str(new_cache_line_size),
+                                             self.dbg.GetInstanceName())
+        self.assertTrue(error.Success(),
+                        property_name + " value was changed successfully")
+
+        # Check that it was set actually.
+        self.assertEqual(get_cache_line_size(), new_cache_line_size)
+
+        # Run any command to initialize CommandInterpreter's execution context.
+        self.runCmd("target list")
+
+        # Test the local property again, is it set to new_cache_line_size?
+        self.assertEqual(get_cache_line_size(), new_cache_line_size)
diff --git a/test/API/python_api/debugger/main.cpp b/test/API/python_api/debugger/main.cpp
new file mode 100644
index 0000000..4b4ca68
--- /dev/null
+++ b/test/API/python_api/debugger/main.cpp
@@ -0,0 +1,9 @@
+// This simple program is to test the lldb Python API SBDebugger.
+
+int func(int val) {
+    return val - 1;
+}
+
+int main (int argc, char const *argv[]) {
+    return func(argc);
+}