Reland "[lldb] Clear thread-creation breakpoints in ProcessGDBRemote::Clear (#134397)" (#135296)

This reapplies commit
232525f069.

The original commit triggered a sanitizer failure when `Target` was
destroyed. In `Target::Destroy`, `DeleteCurrentProcess` was called, but
it did not destroy the thread creation breakpoints for the underlying
`ProcessGDBRemote` because `ProcessGDBRemote::Clear` was not called in
that path.

`Target `then proceeded to destroy its breakpoints, which resulted in a
call to the destructor of a `std::vector` containing the breakpoints.
Through a sequence of complicated events, destroying breakpoints caused
the reference count of the underlying `ProcessGDBRemote` to finally
reach zero. This, in turn, called `ProcessGDBRemote::Clear`, which
attempted to destroy the breakpoints. To do that, it would go back into
the Target's vector of breakpoints, which we are in the middle of
destroying.

We solve this by moving the breakpoint deletion into
`Process:DoDestroy`, which is a virtual Process method that will be
called much earlier.
This commit is contained in:
Felipe de Azevedo Piovezan 2025-04-11 11:46:22 -07:00 committed by GitHub
parent 38e64b1a84
commit c2939b9bf6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 0 deletions

View File

@ -2571,9 +2571,18 @@ Status ProcessGDBRemote::DoDestroy() {
StopAsyncThread();
KillDebugserverProcess();
RemoveNewThreadBreakpoints();
return Status();
}
void ProcessGDBRemote::RemoveNewThreadBreakpoints() {
if (m_thread_create_bp_sp) {
if (TargetSP target_sp = m_target_wp.lock())
target_sp->RemoveBreakpointByID(m_thread_create_bp_sp->GetID());
m_thread_create_bp_sp.reset();
}
}
void ProcessGDBRemote::SetLastStopPacket(
const StringExtractorGDBRemote &response) {
const bool did_exec =

View File

@ -436,6 +436,9 @@ private:
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
/// Remove the breakpoints associated with thread creation from the Target.
void RemoveNewThreadBreakpoints();
// ContinueDelegate interface
void HandleAsyncStdout(llvm::StringRef out) override;
void HandleAsyncMisc(llvm::StringRef data) override;

View File

@ -35,3 +35,23 @@ class TestInterruptThreadNames(TestBase):
for bp in bps:
num_resolved += bp.GetNumResolvedLocations()
self.assertGreater(num_resolved, 0)
@skipUnlessDarwin
def test_internal_bps_deleted_on_relaunch(self):
self.build()
source_file = lldb.SBFileSpec("main.c")
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
self, "initial hello", source_file
)
self.runCmd("break list --internal")
output = self.res.GetOutput()
self.assertEqual(output.count("thread-creation"), 1)
process.Kill()
self.runCmd("run", RUN_SUCCEEDED)
self.runCmd("break list --internal")
output = self.res.GetOutput()
self.assertEqual(output.count("thread-creation"), 1)