Skip to content

Commit df1c7eb

Browse files
authored
[lldb] Speculative fix for crash in Function::GetCallEdges() (#193636)
Replace the unprotected union+bool lazy resolution in DirectCallEdge with `std::call_once`/`std::once_flag`. Multiple threads can call `GetCallee` on the same edge concurrently and the old code had no synchronization on the union discriminator or its contents. This could lead to a corrupted pointer that would explain the crash we're observing sporadically. rdar://175006028
1 parent 3e43205 commit df1c7eb

2 files changed

Lines changed: 37 additions & 48 deletions

File tree

lldb/include/lldb/Symbol/Function.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -342,19 +342,11 @@ class DirectCallEdge : public CallEdge {
342342
Function *GetCallee(ModuleList &images, ExecutionContext &exe_ctx) override;
343343

344344
private:
345-
void ParseSymbolFileAndResolve(ModuleList &images);
345+
Function *ResolveCallee(ModuleList &images);
346346

347-
// Used to describe a direct call.
348-
//
349-
// Either the callee's mangled name or its definition, discriminated by
350-
// \ref resolved.
351-
union {
352-
const char *symbol_name;
353-
Function *def;
354-
} lazy_callee;
355-
356-
/// Whether or not an attempt was made to find the callee's definition.
357-
bool resolved = false;
347+
const char *m_symbol_name;
348+
std::once_flag m_resolved_flag;
349+
Function *m_callee_def = nullptr;
358350
};
359351

360352
/// An indirect call site. Used to represent call sites where the address of

lldb/source/Symbol/Function.cpp

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -158,54 +158,51 @@ lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller,
158158
return GetLoadAddress(GetUnresolvedReturnPCAddress(), caller, target);
159159
}
160160

161-
void DirectCallEdge::ParseSymbolFileAndResolve(ModuleList &images) {
162-
if (resolved)
163-
return;
161+
Function *DirectCallEdge::ResolveCallee(ModuleList &images) {
162+
if (!m_symbol_name)
163+
return nullptr;
164164

165165
Log *log = GetLog(LLDBLog::Step);
166166
LLDB_LOG(log, "DirectCallEdge: Lazily parsing the call graph for {0}",
167-
lazy_callee.symbol_name);
168-
169-
auto resolve_lazy_callee = [&]() -> Function * {
170-
ConstString callee_name{lazy_callee.symbol_name};
171-
SymbolContextList sc_list;
172-
images.FindFunctionSymbols(callee_name, eFunctionNameTypeAuto, sc_list);
173-
size_t num_matches = sc_list.GetSize();
174-
if (num_matches == 0 || !sc_list[0].symbol) {
175-
LLDB_LOG(log,
176-
"DirectCallEdge: Found no symbols for {0}, cannot resolve it",
177-
callee_name);
178-
return nullptr;
179-
}
180-
Address callee_addr = sc_list[0].symbol->GetAddress();
181-
if (!callee_addr.IsValid()) {
182-
LLDB_LOG(log, "DirectCallEdge: Invalid symbol address");
183-
return nullptr;
184-
}
185-
Function *f = callee_addr.CalculateSymbolContextFunction();
186-
if (!f) {
187-
LLDB_LOG(log, "DirectCallEdge: Could not find complete function");
188-
return nullptr;
189-
}
190-
return f;
191-
};
192-
lazy_callee.def = resolve_lazy_callee();
193-
resolved = true;
167+
m_symbol_name);
168+
169+
SymbolContextList sc_list;
170+
images.FindFunctionSymbols(ConstString(m_symbol_name), eFunctionNameTypeAuto,
171+
sc_list);
172+
size_t num_matches = sc_list.GetSize();
173+
if (num_matches == 0 || !sc_list[0].symbol) {
174+
LLDB_LOG(log, "DirectCallEdge: Found no symbols for {0}, cannot resolve it",
175+
m_symbol_name);
176+
return nullptr;
177+
}
178+
179+
Address callee_addr = sc_list[0].symbol->GetAddress();
180+
if (!callee_addr.IsValid()) {
181+
LLDB_LOG(log, "DirectCallEdge: Invalid symbol address");
182+
return nullptr;
183+
}
184+
185+
Function *f = callee_addr.CalculateSymbolContextFunction();
186+
if (!f) {
187+
LLDB_LOG(log, "DirectCallEdge: Could not find complete function");
188+
return nullptr;
189+
}
190+
191+
return f;
194192
}
195193

196194
DirectCallEdge::DirectCallEdge(const char *symbol_name,
197195
AddrType caller_address_type,
198196
lldb::addr_t caller_address, bool is_tail_call,
199197
CallSiteParameterArray &&parameters)
200198
: CallEdge(caller_address_type, caller_address, is_tail_call,
201-
std::move(parameters)) {
202-
lazy_callee.symbol_name = symbol_name;
203-
}
199+
std::move(parameters)),
200+
m_symbol_name(symbol_name) {}
204201

205202
Function *DirectCallEdge::GetCallee(ModuleList &images, ExecutionContext &) {
206-
ParseSymbolFileAndResolve(images);
207-
assert(resolved && "Did not resolve lazy callee");
208-
return lazy_callee.def;
203+
std::call_once(m_resolved_flag,
204+
[&] { m_callee_def = ResolveCallee(images); });
205+
return m_callee_def;
209206
}
210207

211208
IndirectCallEdge::IndirectCallEdge(DWARFExpressionList call_target,

0 commit comments

Comments
 (0)