Skip to content

Commit 12f86ce

Browse files
committed
[lldb] Iterate over a copy of the ModuleList in SearchFilter (llvm#189009)
Avoid a potential deadlock caused by the search filter callback acquiring the target's module lock by iterating over a copy of the list. Fixes llvm#188766 (cherry picked from commit ce1b12e)
1 parent 1999664 commit 12f86ce

3 files changed

Lines changed: 26 additions & 13 deletions

File tree

lldb/source/Core/SearchFilter.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ bool SearchFilter::CompUnitPasses(FileSpec &fileSpec) { return true; }
149149
bool SearchFilter::CompUnitPasses(CompileUnit &compUnit) { return true; }
150150

151151
bool SearchFilter::FunctionPasses(Function &function) {
152-
// This is a slightly cheesy job, but since we don't have finer grained
152+
// This is a slightly cheesy job, but since we don't have finer grained
153153
// filters yet, just checking that the start address passes is probably
154154
// good enough for the base class behavior.
155155
Address addr = function.GetAddress();
@@ -262,7 +262,9 @@ SearchFilter::DoModuleIteration(const SymbolContext &context,
262262
return Searcher::eCallbackReturnContinue;
263263
}
264264

265-
for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) {
265+
ModuleList module_list = m_target_sp->GetImages();
266+
// Since we're iterating over a copy, no need to do any locking.
267+
for (ModuleSP module_sp : module_list.ModulesNoLocking()) {
266268
// If this is the last level supplied, then call the callback directly,
267269
// otherwise descend.
268270
if (!ModulePasses(module_sp))
@@ -422,14 +424,9 @@ void SearchFilterByModule::Search(Searcher &searcher) {
422424
searcher.SearchCallback(*this, empty_sc, nullptr);
423425
}
424426

425-
// If the module file spec is a full path, then we can just find the one
426-
// filespec that passes. Otherwise, we need to go through all modules and
427-
// find the ones that match the file name.
428-
429-
const ModuleList &target_modules = m_target_sp->GetImages();
430-
std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
431-
432-
for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) {
427+
ModuleList module_list = m_target_sp->GetImages();
428+
// Since we're iterating over a copy, no need to do any locking.
429+
for (ModuleSP module_sp : module_list.ModulesNoLocking()) {
433430
if (FileSpec::Match(m_module_spec, module_sp->GetFileSpec())) {
434431
SymbolContext matchingContext(m_target_sp, module_sp);
435432
Searcher::CallbackReturn shouldContinue;
@@ -545,7 +542,9 @@ void SearchFilterByModuleList::Search(Searcher &searcher) {
545542
// If the module file spec is a full path, then we can just find the one
546543
// filespec that passes. Otherwise, we need to go through all modules and
547544
// find the ones that match the file name.
548-
for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) {
545+
ModuleList module_list = m_target_sp->GetImages();
546+
// Since we're iterating over a copy, no need to do any locking.
547+
for (ModuleSP module_sp : module_list.ModulesNoLocking()) {
549548
if (m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) ==
550549
UINT32_MAX)
551550
continue;
@@ -707,7 +706,7 @@ bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) {
707706
cu_spec = sym_ctx.comp_unit->GetPrimaryFile();
708707
if (m_cu_spec_list.FindFileIndex(0, cu_spec, false) == UINT32_MAX)
709708
return false; // Fails the file check
710-
return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp);
709+
return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp);
711710
}
712711

713712
bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) {
@@ -751,7 +750,9 @@ void SearchFilterByModuleListAndCU::Search(Searcher &searcher) {
751750
ModuleList matching_modules;
752751

753752
bool no_modules_in_filter = m_module_spec_list.GetSize() == 0;
754-
for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) {
753+
ModuleList module_list = m_target_sp->GetImages();
754+
// Since we're iterating over a copy, no need to do any locking.
755+
for (ModuleSP module_sp : module_list.ModulesNoLocking()) {
755756
if (!no_modules_in_filter &&
756757
// BEGIN SWIFT
757758
ModulePasses(module_sp) &&
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int main(void) { return 0; }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Test that setting a source regex breakpoint doesn't deadlock when the source
2+
# file has been deleted after compilation.
3+
4+
# RUN: cp %p/Inputs/main.c %t.c
5+
# RUN: %clang_host -g -o %t %t.c
6+
# RUN: rm %t.c
7+
# RUN: %lldb -b -o "br set -p any" %t 2>&1 | FileCheck %s
8+
9+
# CHECK: Breakpoint 1: no locations (pending).
10+
# CHECK-NOT: error
11+
# CHECK-NOT: assert

0 commit comments

Comments
 (0)