Skip to content

Commit 1a8d9a7

Browse files
committed
[lldb] Fix data race in ThreadedCommunication
TSan reports the following race: Write of size 8 at 0x000107707ee8 by main thread: #0 lldb_private::ThreadedCommunication::StartReadThread(...) ThreadedCommunication.cpp:175 #1 lldb_private::Process::SetSTDIOFileDescriptor(...) Process.cpp:4533 rust-lang#2 lldb_private::Platform::DebugProcess(...) Platform.cpp:1121 rust-lang#3 lldb_private::PlatformDarwin::DebugProcess(...) PlatformDarwin.cpp:711 rust-lang#4 lldb_private::Target::Launch(...) Target.cpp:3235 rust-lang#5 CommandObjectProcessLaunch::DoExecute(...) CommandObjectProcess.cpp:256 rust-lang#6 lldb_private::CommandObjectParsed::Execute(...) CommandObject.cpp:751 rust-lang#7 lldb_private::CommandInterpreter::HandleCommand(...) CommandInterpreter.cpp:2054 Previous read of size 8 at 0x000107707ee8 by thread T5: #0 lldb_private::HostThread::IsJoinable(...) const HostThread.cpp:30 #1 lldb_private::ThreadedCommunication::StopReadThread(...) ThreadedCommunication.cpp:192 rust-lang#2 lldb_private::Process::ShouldBroadcastEvent(...) Process.cpp:3420 rust-lang#3 lldb_private::Process::HandlePrivateEvent(...) Process.cpp:3728 rust-lang#4 lldb_private::Process::RunPrivateStateThread(...) Process.cpp:3914 rust-lang#5 std::__1::__function::__func<lldb_private::Process::StartPrivateStateThread(...) function.h:356 rust-lang#6 lldb_private::HostNativeThreadBase::ThreadCreateTrampoline(...) HostNativeThreadBase.cpp:62 rust-lang#7 lldb_private::HostThreadMacOSX::ThreadCreateTrampoline(...) HostThreadMacOSX.mm:18 The problem is the lack of synchronization between starting and stopping the read thread. This patch fixes that by protecting those operations with a mutex. Differential revision: https://reviews.llvm.org/D157361
1 parent bdd17b8 commit 1a8d9a7

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

lldb/include/lldb/Core/ThreadedCommunication.h

+14-2
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,22 @@ class ThreadedCommunication : public Communication, public Broadcaster {
223223
}
224224

225225
protected:
226-
HostThread m_read_thread; ///< The read thread handle in case we need to
227-
/// cancel the thread.
226+
/// The read thread handle in case we need to cancel the thread.
227+
/// @{
228+
HostThread m_read_thread;
229+
std::mutex m_read_thread_mutex;
230+
/// @}
231+
232+
/// Whether the read thread is enabled. This cannot be guarded by the read
233+
/// thread mutex becuase it is used as the control variable to exit the read
234+
/// thread.
228235
std::atomic<bool> m_read_thread_enabled;
236+
237+
/// Whether the read thread is enabled. Technically this could be guarded by
238+
/// the read thread mutex but that needlessly complicates things to
239+
/// check this variables momentary value.
229240
std::atomic<bool> m_read_thread_did_exit;
241+
230242
std::string
231243
m_bytes; ///< A buffer to cache bytes read in the ReadThread function.
232244
std::recursive_mutex m_bytes_mutex; ///< A mutex to protect multi-threaded

lldb/source/Core/ThreadedCommunication.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <chrono>
2424
#include <cstring>
2525
#include <memory>
26+
#include <shared_mutex>
2627

2728
#include <cerrno>
2829
#include <cinttypes>
@@ -155,6 +156,8 @@ size_t ThreadedCommunication::Read(void *dst, size_t dst_len,
155156
}
156157

157158
bool ThreadedCommunication::StartReadThread(Status *error_ptr) {
159+
std::lock_guard<std::mutex> lock(m_read_thread_mutex);
160+
158161
if (error_ptr)
159162
error_ptr->Clear();
160163

@@ -189,6 +192,8 @@ bool ThreadedCommunication::StartReadThread(Status *error_ptr) {
189192
}
190193

191194
bool ThreadedCommunication::StopReadThread(Status *error_ptr) {
195+
std::lock_guard<std::mutex> lock(m_read_thread_mutex);
196+
192197
if (!m_read_thread.IsJoinable())
193198
return true;
194199

@@ -199,13 +204,13 @@ bool ThreadedCommunication::StopReadThread(Status *error_ptr) {
199204

200205
BroadcastEvent(eBroadcastBitReadThreadShouldExit, nullptr);
201206

202-
// error = m_read_thread.Cancel();
203-
204207
Status error = m_read_thread.Join(nullptr);
205208
return error.Success();
206209
}
207210

208211
bool ThreadedCommunication::JoinReadThread(Status *error_ptr) {
212+
std::lock_guard<std::mutex> lock(m_read_thread_mutex);
213+
209214
if (!m_read_thread.IsJoinable())
210215
return true;
211216

0 commit comments

Comments
 (0)