[Lldb-commits] [lldb] [lldb] Fix race condition in Process::WaitForProcessToStop() (PR #144919)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 19 08:48:54 PDT 2025
https://github.com/athierry-oct created https://github.com/llvm/llvm-project/pull/144919
This PR addresses a race condition encountered when using LLDB through the Python scripting interface.
I'm relatively new to LLDB, so feedback is very welcome, especially if there's a more appropriate way to address this issue.
### Bug Description
When running a script that repeatedly calls `debugger.GetListener().WaitForEvent()` in a loop, and at some point invokes `process.Kill()` from within that loop to terminate the session, a race condition can occur if `process.Kill()` is called around the same time a breakpoint is hit.
### Race Condition Details
The issue arises when the following sequence of events happens:
1. The process's **private state** transitions to `stopped` when the breakpoint is hit.
2. `process.Kill()` calls `Process::Destroy()`, which invokes `Process::WaitForProcessToStop()`. At this point:
- `private_state = stopped`
- `public_state = running` (the public state has not yet been updated)
3. The **public stop event** is broadcast **before** the hijack listener is installed.
4. As a result, the stop event is delivered to the **non-hijack listener**.
5. The interrupt request sent by `Process::StopForDestroyOrDetach()` is ignored because the process is already stopped (`private_state = stopped`).
6. No public stop event reaches the hijack listener.
7. `Process::WaitForProcessToStop()` hangs waiting for a public stop event, but the event is never received.
8. `process.Kill()` times out after 20 seconds
### Fix Summary
This patch modifies `Process::WaitForProcessToStop()` to ensure that any pending events in the non-hijack listener queue are processed before checking the hijack listener. This guarantees that any missed public state change events are handled, preventing the hang.
### Additional Context
A discussion of this issue, including a script to reproduce the bug, can be found here:
[LLDB hangs when killing process at the same time a breakpoint is hit](https://discourse.llvm.org/t/lldb-hangs-when-killing-process-at-the-same-time-a-breakpoint-is-hit)
>From dfe59d058645bcf83e7956cec14ad43a7ada5349 Mon Sep 17 00:00:00 2001
From: Adrien Thierry <adrien.thierry at octasic.com>
Date: Thu, 19 Jun 2025 10:00:46 -0400
Subject: [PATCH] [lldb] Fix race condition in Process::WaitForProcessToStop()
This patch addresses a race condition that can occur when a script using
the Python API calls SBProcess::Kill() around the same time a breakpoint
is hit.
If a stop event is broadcast before the hijack listener is installed, it
may be delivered to the default listener and missed entirely by the
hijack listener. This causes Process::WaitForProcessToStop() to hang
until it times out, waiting for a public stop event that is never
received.
To fix this, Process::WaitForProcessToStop() now checks for pending
events in the non-hijack listener before falling back to the hijack
listener, ensuring that any missed public state change events are
properly handled.
---
lldb/source/Target/Process.cpp | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 61a3d05bc3746..c75acdb1ecd80 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -683,7 +683,18 @@ StateType Process::WaitForProcessToStop(
while (state != eStateInvalid) {
EventSP event_sp;
- state = GetStateChangedEvents(event_sp, timeout, hijack_listener_sp);
+
+ // A stop event may have been queued in the non-hijack listener before
+ // the hijack listener was installed (e.g., if a breakpoint is hit
+ // around the same time SBProcess::Kill() is called). Check and process
+ // those events first to avoid missing them.
+ if (PeekAtStateChangedEvents()) {
+ // Get event from non-hijack listener
+ state = GetStateChangedEvents(event_sp, timeout, nullptr);
+ } else {
+ state = GetStateChangedEvents(event_sp, timeout, hijack_listener_sp);
+ }
+
if (event_sp_ptr && event_sp)
*event_sp_ptr = event_sp;
More information about the lldb-commits
mailing list