This is an archive of the discontinued LLVM Phabricator instance.

[lldb] Properly protect the Communication class with reader/writer lock
AbandonedPublic

Authored by JDevlieghere on Aug 4 2023, 4:41 PM.

Details

Summary

The Communication class was trying to (ab)use unique_ptr's atomic properties to protected it from concurrent access. Replace it with a regular reader/writer lock.

Diff Detail

Event Timeline

JDevlieghere created this revision.Aug 4 2023, 4:41 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 4 2023, 4:41 PM
JDevlieghere requested review of this revision.Aug 4 2023, 4:41 PM
augusto2112 accepted this revision.Aug 4 2023, 5:02 PM

On the description you mention unique_ptr but I only see shared_ptr here. Was that a typo or do you mean that users of this class kept it behind a unique_ptr?

In any case I think this change is great.

lldb/source/Core/Communication.cpp
35

Do you think it's possible that between the call to Clear and this lock someone acquires the lock?

This revision is now accepted and ready to land.Aug 4 2023, 5:02 PM
bulbazord added inline comments.
lldb/source/Core/Communication.cpp
34–35

I think this one may be slightly incorrect. Here's how I imagine it going wrong:

  • Thread 1 calls Connect. It only runs Clear() (which disconnects) and then Thread 2 is scheduled.
  • Thread 2 then calls Connect. It also only runs Clear() and then Thread 1 is scheduled.
  • Thread 1 grabs the lock, connects, and exits.
  • Thread 2 also grabs the lock, connects, and exits.

I'm not sure how gracefully Connection::Connect handles another connection if not properly disconnected from the first url beforehand. Reading through some of the Connection derived class implementations of Connect I'm not sure exactly what will happen though. The documentation isn't much clearer either...

JDevlieghere added inline comments.Aug 4 2023, 5:26 PM
lldb/source/Core/Communication.cpp
35

Yes, you're both correct. We can't use the ClearUnlocked trick here because it's Disconnect that locks and Clear is virtual. I'll need to play around with this. Maybe we don't need a Clear and we can call DisconnectUnlocked directly ?

bulbazord added inline comments.Aug 4 2023, 5:34 PM
lldb/source/Core/Communication.cpp
35

Yeah calling Disconnect in an unlocked fashion would solve that if you called it after locking in Connect.

  • Remove Communication::Clear method
JDevlieghere added inline comments.Aug 6 2023, 9:20 PM
lldb/source/Core/ThreadedCommunication.cpp
63–67

This wasn't used: nobody called Clear on an instance of ThreadedCommunication.

lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
560

According to the comment on line 541 this is wrong:

 // We are running and we can't interrupt a running kernel, so we need to
// just close the connection to the kernel and hope for the best

m_comm is an instance of CommunicationKDP which didn't override Communication::Clear and hence just called Disconnected.

bulbazord accepted this revision.Aug 7 2023, 1:27 PM

LGTM

lldb/source/Core/Communication.cpp
115–118

Unrelated to your patch but something about this is triggering my spider sense. Is it possible that status == eConnectionStatusSuccess while WriteUnlocked returns 0? This might end up in an infinite loop then, no?

Obviously you don't need to address this since it's unrelated, but something to think about for resiliency.

JDevlieghere abandoned this revision.Aug 7 2023, 9:46 PM

Abandoning this in favor of D157347