TSan reports the following data race:
Write of size 4 at 0x000109e0b160 by thread T2 (mutexes: write M0, write M1): #0 lldb_private::NativeFile::Close() File.cpp:329 (liblldb.18.0.0git.dylib:arm64+0x58dac0) #1 lldb_private::ConnectionFileDescriptor::Disconnect(lldb_private::Status*) ConnectionFileDescriptorPosix.cpp:232 (liblldb.18.0.0git.dylib:arm64+0x5bad6c) #2 lldb_private::Communication::Disconnect(lldb_private::Status*) Communication.cpp:61 (liblldb.18.0.0git.dylib:arm64+0x451f04) #3 lldb_private::process_gdb_remote::ProcessGDBRemote::DidExit() ProcessGDBRemote.cpp:1164 (liblldb.18.0.0git.dylib:arm64+0xadfd80) #4 lldb_private::Process::SetExitStatus(int, char const*) Process.cpp:1097 (liblldb.18.0.0git.dylib:arm64+0x6ed338) #5 lldb_private::process_gdb_remote::ProcessGDBRemote::MonitorDebugserverProcess(std::__1::weak_ptr<lldb_private::process_gdb_remote::ProcessGDBRemote>, unsigned long long, int, int) ProcessGDBRemote.cpp:3387 (liblldb.18.0.0git.dylib:arm64+0xae9464) Previous read of size 4 at 0x000109e0b160 by main thread (mutexes: write M2): #0 lldb_private::NativeFile::IsValid() const File.h:393 (liblldb.18.0.0git.dylib:arm64+0x590830) #1 lldb_private::ConnectionFileDescriptor::IsConnected() const ConnectionFileDescriptorPosix.cpp:121 (liblldb.18.0.0git.dylib:arm64+0x5b8ab4) #2 lldb_private::Communication::IsConnected() const Communication.cpp:79 (liblldb.18.0.0git.dylib:arm64+0x451fcc) #3 lldb_private::process_gdb_remote::GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote&, lldb_private::Timeout<std::__1::ratio<1l, 1000000l>>, bool) GDBRemoteCommunication.cpp:256 (liblldb.18.0.0git.dylib:arm64+0xaac060) #4 lldb_private::process_gdb_remote::GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote&, lldb_private::Timeout<std::__1::ratio<1l, 1000000l>>, bool) GDBRemoteCommunication.cpp:244 (liblldb.18.0.0git.dylib:arm64+0xaabe78) #5 lldb_private::process_gdb_remote::GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(llvm::StringRef, StringExtractorGDBRemote&) GDBRemoteClientBase.cpp:246 (liblldb.18.0.0git.dylib:arm64+0xaaa184)
I tried fixing the problem at the ConnectionFileDescriptor level, but the underlying problem is that NativeFile isn't thread safe. NativeFile can hold a file descriptor and/or a file stream. Throughout its implementation, it would check if the descriptor or stream is valid and than do something based on that. While that works in a single threaded environment, nothing prevents another thread from modifying the descriptor or stream between the IsValid check and when it's actually being used. This patch prevents such issues by returning a ValueGuard RAII object. As long as the object is in scope, the value is guaranteed by a lock.
Hmm, this should be okay since URVO is mandatory as of C++17 (meaning this will not perform a copy and potentially screw up the locking mechanism).