Skip to content

Commit 0fb1193

Browse files
committed
[lldb/Target] Track originating StackFrameList to avoid circular dependencies
This change adds tracking of the StackFrameList that created each frame by storing a weak pointer (m_frame_list_wp) in both StackFrame and ExecutionContextRef. When resolving frames through ExecutionContextRef::GetFrameSP(), the code now first attempts to use the remembered frame list instead of immediately calling Thread::GetStackFrameList(). This breaks circular dependencies that can occur during frame provider initialization, where creating a frame provider might trigger ExecutionContext resolution, which would then call back into Thread::GetStackFrameList(), creating an infinite loop. The StackFrameList now sets m_frame_list_wp on every frame it creates, and a new virtual method GetOriginatingStackFrameList() allows frames to expose their source list. Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent d3f0720 commit 0fb1193

File tree

5 files changed

+43
-4
lines changed

5 files changed

+43
-4
lines changed

lldb/include/lldb/Target/ExecutionContext.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,10 @@ class ExecutionContextRef {
268268
m_tid = LLDB_INVALID_THREAD_ID;
269269
}
270270

271-
void ClearFrame() { m_stack_id.Clear(); }
271+
void ClearFrame() {
272+
m_stack_id.Clear();
273+
m_frame_list_wp.reset();
274+
}
272275

273276
protected:
274277
// Member variables
@@ -279,7 +282,11 @@ class ExecutionContextRef {
279282
///< object refers to in case the
280283
/// backing object changes
281284
StackID m_stack_id; ///< The stack ID that this object refers to in case the
282-
///backing object changes
285+
///< backing object changes
286+
mutable lldb::StackFrameListWP m_frame_list_wp; ///< Weak reference to the
287+
///< frame list that created
288+
///< this frame, used to avoid
289+
///< circular dependencies
283290
};
284291

285292
/// \class ExecutionContext ExecutionContext.h

lldb/include/lldb/Target/StackFrame.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,19 @@ class StackFrame : public ExecutionContextScope,
544544

545545
virtual lldb::RecognizedStackFrameSP GetRecognizedFrame();
546546

547+
/// Get the StackFrameList that created this frame.
548+
///
549+
/// Returns the StackFrameList that originally created this frame, allowing
550+
/// frames to resolve execution contexts without calling
551+
/// Thread::GetStackFrameList(), which can cause circular dependencies
552+
/// during frame provider initialization.
553+
///
554+
/// \return
555+
/// The StackFrameList that created this frame, or nullptr if not set.
556+
virtual lldb::StackFrameListSP GetOriginatingStackFrameList() const {
557+
return m_frame_list_wp.lock();
558+
}
559+
547560
protected:
548561
friend class BorrowedStackFrame;
549562
friend class StackFrameList;
@@ -587,6 +600,7 @@ class StackFrame : public ExecutionContextScope,
587600
/// well as any other frame with the same trait.
588601
bool m_behaves_like_zeroth_frame;
589602
lldb::VariableListSP m_variable_list_sp;
603+
lldb::StackFrameListWP m_frame_list_wp;
590604
/// Value objects for each variable in m_variable_list_sp.
591605
ValueObjectList m_variable_list_value_objects;
592606
std::optional<lldb::RecognizedStackFrameSP> m_recognized_frame_sp;

lldb/include/lldb/lldb-forward.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ typedef std::unique_ptr<lldb_private::SourceManager> SourceManagerUP;
439439
typedef std::shared_ptr<lldb_private::StackFrame> StackFrameSP;
440440
typedef std::weak_ptr<lldb_private::StackFrame> StackFrameWP;
441441
typedef std::shared_ptr<lldb_private::StackFrameList> StackFrameListSP;
442+
typedef std::weak_ptr<lldb_private::StackFrameList> StackFrameListWP;
442443
typedef std::shared_ptr<lldb_private::StackFrameRecognizer>
443444
StackFrameRecognizerSP;
444445
typedef std::unique_ptr<lldb_private::StackFrameRecognizerManager>

lldb/source/Target/ExecutionContext.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,10 +466,13 @@ operator=(const ExecutionContext &exe_ctx) {
466466
else
467467
m_tid = LLDB_INVALID_THREAD_ID;
468468
lldb::StackFrameSP frame_sp(exe_ctx.GetFrameSP());
469-
if (frame_sp)
469+
if (frame_sp) {
470470
m_stack_id = frame_sp->GetStackID();
471-
else
471+
m_frame_list_wp = frame_sp->GetOriginatingStackFrameList();
472+
} else {
472473
m_stack_id.Clear();
474+
m_frame_list_wp.reset();
475+
}
473476
return *this;
474477
}
475478

@@ -511,6 +514,7 @@ void ExecutionContextRef::SetThreadSP(const lldb::ThreadSP &thread_sp) {
511514
void ExecutionContextRef::SetFrameSP(const lldb::StackFrameSP &frame_sp) {
512515
if (frame_sp) {
513516
m_stack_id = frame_sp->GetStackID();
517+
m_frame_list_wp = frame_sp->GetOriginatingStackFrameList();
514518
SetThreadSP(frame_sp->GetThread());
515519
} else {
516520
ClearFrame();
@@ -638,6 +642,14 @@ lldb::ThreadSP ExecutionContextRef::GetThreadSP() const {
638642

639643
lldb::StackFrameSP ExecutionContextRef::GetFrameSP() const {
640644
if (m_stack_id.IsValid()) {
645+
// Try the remembered frame list first to avoid circular dependencies
646+
// during frame provider initialization
647+
if (auto frame_list_sp = m_frame_list_wp.lock()) {
648+
if (auto frame_sp = frame_list_sp->GetFrameWithStackID(m_stack_id))
649+
return frame_sp;
650+
}
651+
652+
// Fallback: ask the thread (might trigger re-initialization)
641653
lldb::ThreadSP thread_sp(GetThreadSP());
642654
if (thread_sp)
643655
return thread_sp->GetFrameWithStackID(m_stack_id);

lldb/source/Target/StackFrameList.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
330330
m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,
331331
cfa_is_valid, pc, StackFrame::Kind::Regular, artificial,
332332
behaves_like_zeroth_frame, &sc);
333+
synth_frame->m_frame_list_wp = shared_from_this();
333334
m_frames.push_back(synth_frame);
334335
LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
335336
}
@@ -445,6 +446,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
445446
unwind_frame_sp = std::make_shared<StackFrame>(
446447
m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp,
447448
cfa, pc, behaves_like_zeroth_frame, nullptr);
449+
unwind_frame_sp->m_frame_list_wp = shared_from_this();
448450
m_frames.push_back(unwind_frame_sp);
449451
}
450452
} else {
@@ -479,6 +481,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
479481
// although its concrete index will stay the same.
480482
SynthesizeTailCallFrames(*unwind_frame_sp.get());
481483

484+
unwind_frame_sp->m_frame_list_wp = shared_from_this();
482485
m_frames.push_back(unwind_frame_sp);
483486
}
484487

@@ -503,6 +506,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
503506
unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address,
504507
behaves_like_zeroth_frame, &next_frame_sc));
505508

509+
frame_sp->m_frame_list_wp = shared_from_this();
506510
m_frames.push_back(frame_sp);
507511
unwind_sc = next_frame_sc;
508512
curr_frame_address = next_frame_address;
@@ -559,6 +563,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
559563
prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame);
560564
// Now copy the fixed up previous frame into the current frames so the
561565
// pointer doesn't change.
566+
prev_frame_sp->m_frame_list_wp = shared_from_this();
562567
m_frames[curr_frame_idx] = prev_frame_sp;
563568

564569
#if defined(DEBUG_STACK_FRAMES)

0 commit comments

Comments
 (0)