Skip to content

Commit e907e8b

Browse files
[lldb] Fix ThreadPlanStepOut::DoPlanExplainsStop inspection of BreakpointSite (llvm#169799)
Suppose two threads are performing the exact same step out plan. They will both have an internal breakpoint set at their parent frame. Now supposed both of those breakpoints are in the same address (i.e. the same BreakpointSite). At the end of `ThreadPlanStepOut::DoPlanExplainsStop`, we see this: ``` // If there was only one owner, then we're done. But if we also hit // some user breakpoint on our way out, we should mark ourselves as // done, but also not claim to explain the stop, since it is more // important to report the user breakpoint than the step out // completion. if (site_sp->GetNumberOfConstituents() == 1) return true; ``` In other words, the plan looks at the name number of constituents of the site to decide whether it explains the stop, the logic being that a _user_ might have put a breakpoint there. However, the implementation is not correct; in particular, it will fail in the situation described above. We should only care about non-internal breakpoints that would stop for the current thread. It is tricky to test this, as it depends on the timing of threads, but I was able to consistently reproduce the issue with a swift program using concurrency. rdar://165481473 (cherry picked from commit c0f0936)
1 parent 03bec58 commit e907e8b

File tree

3 files changed

+24
-7
lines changed

3 files changed

+24
-7
lines changed

lldb/include/lldb/Breakpoint/BreakpointSite.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
156156
/// would be valid for this thread, false otherwise.
157157
bool ValidForThisThread(Thread &thread);
158158

159+
/// Returns true if at least one constituent is both public and valid for
160+
/// `thread`.
161+
bool ContainsUserBreakpointForThread(Thread &thread);
162+
159163
/// Print a description of this breakpoint site to the stream \a s.
160164
/// GetDescription tells you about the breakpoint site's constituents. Use
161165
/// BreakpointSite::Dump(Stream *) to get information about the breakpoint

lldb/source/Breakpoint/BreakpointSite.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,22 @@ bool BreakpointSite::ValidForThisThread(Thread &thread) {
168168
return m_constituents.ValidForThisThread(thread);
169169
}
170170

171+
bool BreakpointSite::ContainsUserBreakpointForThread(Thread &thread) {
172+
if (ThreadSP backed_thread = thread.GetBackedThread())
173+
return ContainsUserBreakpointForThread(*backed_thread);
174+
175+
std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
176+
for (const BreakpointLocationSP &bp_loc :
177+
m_constituents.BreakpointLocations()) {
178+
const Breakpoint &bp = bp_loc->GetBreakpoint();
179+
if (bp.IsInternal())
180+
continue;
181+
if (bp_loc->ValidForThisThread(thread))
182+
return true;
183+
}
184+
return false;
185+
}
186+
171187
void BreakpointSite::BumpHitCounts() {
172188
std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
173189
for (BreakpointLocationSP loc_sp : m_constituents.BreakpointLocations()) {

lldb/source/Target/ThreadPlanStepOut.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -390,13 +390,10 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
390390
}
391391
}
392392

393-
// If there was only one owner, then we're done. But if we also hit
394-
// some user breakpoint on our way out, we should mark ourselves as
395-
// done, but also not claim to explain the stop, since it is more
396-
// important to report the user breakpoint than the step out
397-
// completion.
398-
399-
if (site_sp->GetNumberOfConstituents() == 1)
393+
// If the thread also hit a user breakpoint on its way out, the plan is
394+
// done but should not claim to explain the stop. It is more important
395+
// to report the user breakpoint than the step out completion.
396+
if (!site_sp->ContainsUserBreakpointForThread(GetThread()))
400397
return true;
401398
}
402399
return false;

0 commit comments

Comments
 (0)