[lldb] Don't adopt in the ExecutionContext from auto-continue events#191433
Merged
Conversation
When a breakpoint auto-continues, the event handler receives a "stopped but restarted" event. During the transition where we step over the breakpoint (before continuing), the public state hasn't yet been set to running. This caused the `DefaultEventHandler` to call `ExecutionContextRef` with `adopt_selected=true`, which would fetch stale thread/frame state and needlessly (and incorrectly) interrupt the target to compute the execution context (used by the statusline). This PR fixes that by not doing that. Fixes llvm#190956 Co-authored-by: Jim Ingham <jingham@apple.com>
Member
|
@llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) ChangesWhen a breakpoint auto-continues, the event handler receives a "stopped but restarted" event. During the transition where we step over the breakpoint (before continuing), the public state hasn't yet been set to running. This caused the Fixes #190956 Full diff: https://github.com/llvm/llvm-project/pull/191433.diff 5 Files Affected:
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 9deef5a4ae503..a9129c2a6aef1 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -2246,10 +2246,19 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
uint32_t event_type = event_sp->GetType();
llvm::StringRef broadcaster_class(broadcaster->GetBroadcasterClass());
if (broadcaster_class == broadcaster_class_process) {
- if (ProcessSP process_sp = HandleProcessEvent(event_sp))
+ if (ProcessSP process_sp = HandleProcessEvent(event_sp)) {
+ // Don't pass adopt_selected = true if this is a stop for an
+ // auto-continue event (e.g. an auto-continue breakpoint). We
+ // would be fetching stale state, since the process resumed since
+ // this event, and we'd needlessly interrupt the target to do so.
+ const bool adopt_selected =
+ process_sp->GetPrivateState() == eStateStopped &&
+ !Process::ProcessEventData::GetRestartedFromEvent(
+ event_sp.get());
if (!RequiresFollowChildWorkaround(*process_sp))
- exe_ctx_ref = ExecutionContextRef(process_sp.get(),
- /*adopt_selected=*/true);
+ exe_ctx_ref =
+ ExecutionContextRef(process_sp.get(), adopt_selected);
+ }
} else if (broadcaster_class == broadcaster_class_target) {
if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
event_sp.get())) {
diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/Makefile b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/Makefile
new file mode 100644
index 0000000000000..c46619c662348
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/TestBreakpointCommandAutoContinue.py b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/TestBreakpointCommandAutoContinue.py
new file mode 100644
index 0000000000000..ebf75f8563256
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/TestBreakpointCommandAutoContinue.py
@@ -0,0 +1,40 @@
+"""
+Regression test for a bug in the default event handler (specifically when
+redrawing the statusline) that triggered when auto-continuing from a
+breakpoint.
+"""
+
+import os
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.lldbpexpect import PExpectTest
+
+
+@skipIfAsan
+@skipIfEditlineSupportMissing
+class BreakpointCommandAutoContinueTestCase(PExpectTest):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def test_breakpoint_command_auto_continue(self):
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ bpcmd = os.path.join(self.getSourceDir(), "bpcmd.py")
+
+ self.launch(executable=exe, timeout=60, dimensions=(25, 80))
+
+ self.expect("breakpoint set --name break_here", substrs=["Breakpoint 1"])
+ self.expect(
+ f"command script import {bpcmd}",
+ )
+ self.expect(
+ "breakpoint command add --python-function bpcmd.write_ok 1",
+ )
+
+ # Run the program. It should complete successfully (print PASSED).
+ # Without the fix, the debugger would interrupt the process when
+ # processing auto-continue events to fetch stale thread/frame state
+ # for the statusline, causing the memory writes to fail and the
+ # program to abort.
+ self.child.sendline("run")
+ self.child.expect("PASSED", timeout=30)
diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/bpcmd.py b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/bpcmd.py
new file mode 100644
index 0000000000000..4205732630eac
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/bpcmd.py
@@ -0,0 +1,11 @@
+import lldb
+
+
+def write_ok(frame, bp_loc, internal_dict):
+ """Write "OK" into the buffer pointed to by 'buf' and auto-continue."""
+ buf = frame.FindVariable("buf")
+ addr = buf.GetValueAsUnsigned()
+ if addr != 0:
+ error = lldb.SBError()
+ frame.GetThread().GetProcess().WriteMemory(addr, b"OK", error)
+ return False
diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/main.cpp b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/main.cpp
new file mode 100644
index 0000000000000..9657ab08b204f
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command_auto_continue/main.cpp
@@ -0,0 +1,35 @@
+#include <pthread.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstring>
+
+__attribute__((noinline)) void break_here(char *buf) {
+ // Memory barrier to keep the function body non-empty.
+ asm volatile("" ::: "memory");
+}
+
+void *test_thread(void *) {
+ char buf[1024];
+ for (int i = 0; i < 200; i++) {
+ memset(buf, 0, sizeof(buf));
+ break_here(buf);
+ if (memcmp(buf, "OK", 2) != 0) {
+ printf("FAILED at iteration %d\n", i);
+ _exit(1);
+ }
+ usleep(50);
+ }
+ return nullptr;
+}
+
+int main() {
+ pthread_t thread;
+ if (pthread_create(&thread, nullptr, test_thread, nullptr) != 0) {
+ perror("pthread_create");
+ return 1;
+ }
+ pthread_join(thread, nullptr);
+ printf("PASSED\n");
+ return 0;
+}
|
alexfh
pushed a commit
to alexfh/llvm-project
that referenced
this pull request
Apr 18, 2026
…lvm#191433) When a breakpoint auto-continues, the event handler receives a "stopped but restarted" event. During the transition where we step over the breakpoint (before continuing), the public state hasn't yet been set to running. This caused the `DefaultEventHandler` to call `ExecutionContextRef` with `adopt_selected=true`, which would fetch stale thread/frame state and needlessly (and incorrectly) interrupt the target to compute the execution context (used by the statusline). This PR fixes that by not doing that. Fixes llvm#190956 Co-authored-by: Jim Ingham <jingham@apple.com>
KHicketts
pushed a commit
to KHicketts/llvm-project
that referenced
this pull request
Apr 30, 2026
…lvm#191433) When a breakpoint auto-continues, the event handler receives a "stopped but restarted" event. During the transition where we step over the breakpoint (before continuing), the public state hasn't yet been set to running. This caused the `DefaultEventHandler` to call `ExecutionContextRef` with `adopt_selected=true`, which would fetch stale thread/frame state and needlessly (and incorrectly) interrupt the target to compute the execution context (used by the statusline). This PR fixes that by not doing that. Fixes llvm#190956 Co-authored-by: Jim Ingham <jingham@apple.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a breakpoint auto-continues, the event handler receives a "stopped but restarted" event. During the transition where we step over the breakpoint (before continuing), the public state hasn't yet been set to running. This caused the
DefaultEventHandlerto callExecutionContextRefwithadopt_selected=true, which would fetch stale thread/frame state and needlessly (and incorrectly) interrupt the target to compute the execution context (used by the statusline). This PR fixes that by not doing that.Fixes #190956