diff --git a/lldb/include/lldb/Target/StackFrameList.h b/lldb/include/lldb/Target/StackFrameList.h index 8a66296346f2d..e5a6e942d7431 100644 --- a/lldb/include/lldb/Target/StackFrameList.h +++ b/lldb/include/lldb/Target/StackFrameList.h @@ -174,6 +174,11 @@ class StackFrameList { /// change the frame if this is the first time GetSelectedFrame is called. std::optional m_selected_frame_idx; + /// Protect access to m_selected_frame_idx. Always acquire after m_list_mutex + /// to avoid lock inversion. A recursive mutex because GetSelectedFrameIndex + /// may indirectly call SetSelectedFrame. + std::recursive_mutex m_selected_frame_mutex; + /// The number of concrete frames fetched while filling the frame list. This /// is only used when synthetic frames are enabled. uint32_t m_concrete_frames_fetched; diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 16cd2548c2784..aedfc52cfb4cb 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -783,6 +783,8 @@ void StackFrameList::SelectMostRelevantFrame() { uint32_t StackFrameList::GetSelectedFrameIndex(SelectMostRelevant select_most_relevant) { + std::lock_guard guard(m_selected_frame_mutex); + if (!m_selected_frame_idx && select_most_relevant) SelectMostRelevantFrame(); if (!m_selected_frame_idx) { @@ -798,6 +800,8 @@ StackFrameList::GetSelectedFrameIndex(SelectMostRelevant select_most_relevant) { uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) { std::shared_lock guard(m_list_mutex); + std::lock_guard selected_frame_guard( + m_selected_frame_mutex); const_iterator pos; const_iterator begin = m_frames.begin(); @@ -851,6 +855,8 @@ void StackFrameList::Clear() { std::unique_lock guard(m_list_mutex); m_frames.clear(); m_concrete_frames_fetched = 0; + std::lock_guard selected_frame_guard( + m_selected_frame_mutex); m_selected_frame_idx.reset(); }