[Lldb-commits] [lldb] b0f3cd1 - [lldb][windows] fix a race condition in IO reader thread (#194422)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Apr 28 06:58:02 PDT 2026
Author: Charles Zablit
Date: 2026-04-28T14:57:56+01:00
New Revision: b0f3cd1020a862244653f0445fbd52a1a1cad887
URL: https://github.com/llvm/llvm-project/commit/b0f3cd1020a862244653f0445fbd52a1a1cad887
DIFF: https://github.com/llvm/llvm-project/commit/b0f3cd1020a862244653f0445fbd52a1a1cad887.diff
LOG: [lldb][windows] fix a race condition in IO reader thread (#194422)
Added:
Modified:
lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index c0c8be8bd62b8..73374a7c07bde 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -740,9 +740,41 @@ ProcessWindows::OnDebugException(bool first_chance,
return ExceptionResult::SendToApplication;
}
+ // Drain any in-flight process output before announcing the stop. The I/O
+ // reader thread and this debug-event thread run concurrently. Without
+ // synchronization the eBroadcastBitStateChanged(Stopped) event can reach
+ // the Debugger event thread before the preceding eBroadcastBitSTDOUT
+ // events.
+ auto drain_stdout = [this] {
+ if (!m_stdio_communication.ReadThreadIsRunning())
+ return;
+ m_stdio_communication.SynchronizeWithReadThread();
+ if (!m_pty || m_pty->GetMode() != PseudoConsole::Mode::ConPTY)
+ return;
+
+ HANDLE pipe = m_pty->GetSTDOUTHandle();
+ for (int consec_empty = 0; consec_empty < 3;) {
+ if (!m_stdio_communication.ReadThreadIsRunning())
+ break;
+ DWORD avail = 0;
+ // PeekNamedPipe is thread safe.
+ if (!::PeekNamedPipe(pipe, nullptr, 0, nullptr, &avail, nullptr))
+ break;
+ if (avail > 0) {
+ consec_empty = 0;
+ m_stdio_communication.SynchronizeWithReadThread();
+ } else {
+ ++consec_empty;
+ if (consec_empty < 3)
+ ::SleepEx(1, FALSE);
+ }
+ }
+ };
+
if (!first_chance) {
// Not any second chance exception is an application crash by definition.
// It may be an expression evaluation crash.
+ drain_stdout();
SetPrivateState(eStateStopped);
}
@@ -763,10 +795,12 @@ ProcessWindows::OnDebugException(bool first_chance,
LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
record.GetExceptionAddress());
}
+ drain_stdout();
SetPrivateState(eStateStopped);
break;
case EXCEPTION_SINGLE_STEP:
result = ExceptionResult::BreakInDebugger;
+ drain_stdout();
SetPrivateState(eStateStopped);
break;
default:
More information about the lldb-commits
mailing list