https://github.com/da-viper created 
https://github.com/llvm/llvm-project/pull/179202

We are sending an invalid thread error on a valid thread because the process is 
not in a stopped state.
Send a `notStoppedError` so the client can retry at a later state after we have 
sent a stopped event.

This can happen when debugging a large binary and the user spams the step over 
button.

>From 451ce6176defea642a456337230ba013920771ad Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <[email protected]>
Date: Mon, 2 Feb 2026 10:37:25 +0000
Subject: [PATCH] [lldb-dap] Check the process state before thread or frame
 validation.

We are sending an invalid thread error on a valid thread
because the process is not in a stopped state.
Send a `notStoppedError` so the client can retry at a later state
after we have sent a stopped event.
---
 lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp       | 6 +++---
 lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp | 5 +++++
 lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp     | 6 +++---
 lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp    | 8 ++++----
 4 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp
index 2b48350dfba1b..ecb086b36c817 100644
--- a/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp
@@ -27,13 +27,13 @@ namespace lldb_dap {
 /// adapter first sends the response and then a `stopped` event (with reason
 /// `step`) after the step has completed.
 Error NextRequestHandler::Run(const NextArguments &args) const {
+  if (!SBDebugger::StateIsStoppedState(dap.target.GetProcess().GetState()))
+    return make_error<NotStoppedError>();
+
   lldb::SBThread thread = dap.GetLLDBThread(args.threadId);
   if (!thread.IsValid())
     return make_error<DAPError>("invalid thread");
 
-  if (!SBDebugger::StateIsStoppedState(dap.target.GetProcess().GetState()))
-    return make_error<NotStoppedError>();
-
   // Remember the thread ID that caused the resume so we can set the
   // "threadCausedFocus" boolean value in the "stopped" events.
   dap.focus_tid = thread.GetThreadID();
diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
index 7064d356a6479..9dc9b3735734d 100644
--- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
@@ -14,6 +14,7 @@
 #include "ProtocolUtils.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBStream.h"
+#include "lldb/lldb-enumerations.h"
 
 using namespace lldb_dap;
 using namespace lldb_dap::protocol;
@@ -189,6 +190,10 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread 
&thread,
 
 llvm::Expected<protocol::StackTraceResponseBody>
 StackTraceRequestHandler::Run(const protocol::StackTraceArguments &args) const 
{
+  const lldb::StateType process_state = dap.target.GetProcess().GetState();
+  if (!lldb::SBDebugger::StateIsStoppedState(process_state))
+    return llvm::make_error<NotStoppedError>();
+
   lldb::SBThread thread = dap.GetLLDBThread(args.threadId);
   if (!thread.IsValid())
     return llvm::make_error<DAPError>("invalid thread");
diff --git a/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp
index 6742c791a5486..8f11d10389b1c 100644
--- a/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp
@@ -32,6 +32,9 @@ namespace lldb_dap {
 // possible targets for a given source line can be retrieved via the
 // `stepInTargets` request.
 Error StepInRequestHandler::Run(const StepInArguments &args) const {
+  if (!SBDebugger::StateIsStoppedState(dap.target.GetProcess().GetState()))
+    return make_error<NotStoppedError>();
+
   SBThread thread = dap.GetLLDBThread(args.threadId);
   if (!thread.IsValid())
     return make_error<DAPError>("invalid thread");
@@ -40,9 +43,6 @@ Error StepInRequestHandler::Run(const StepInArguments &args) 
const {
   // "threadCausedFocus" boolean value in the "stopped" events.
   dap.focus_tid = thread.GetThreadID();
 
-  if (!SBDebugger::StateIsStoppedState(dap.target.GetProcess().GetState()))
-    return make_error<NotStoppedError>();
-
   lldb::SBError error;
   if (args.granularity == eSteppingGranularityInstruction) {
     thread.StepInstruction(/*step_over=*/false, error);
diff --git a/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
index e896e03720b6b..baf790a5f27f0 100644
--- a/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
@@ -14,6 +14,7 @@
 #include "llvm/Support/Error.h"
 
 using namespace llvm;
+using namespace lldb;
 using namespace lldb_dap::protocol;
 
 namespace lldb_dap {
@@ -29,14 +30,13 @@ namespace lldb_dap {
 /// The debug adapter first sends the response and then a `stopped` event (with
 /// reason `step`) after the step has completed."
 Error StepOutRequestHandler::Run(const StepOutArguments &arguments) const {
+  if (!SBDebugger::StateIsStoppedState(dap.target.GetProcess().GetState()))
+    return make_error<NotStoppedError>();
+
   lldb::SBThread thread = dap.GetLLDBThread(arguments.threadId);
   if (!thread.IsValid())
     return make_error<DAPError>("invalid thread");
 
-  if (!lldb::SBDebugger::StateIsStoppedState(
-          dap.target.GetProcess().GetState()))
-    return make_error<NotStoppedError>();
-
   // Remember the thread ID that caused the resume so we can set the
   // "threadCausedFocus" boolean value in the "stopped" events.
   dap.focus_tid = thread.GetThreadID();

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to