Skip to content

Commit b64d0a2

Browse files
committed
Fix a race condition.
The reader lock must be acquired before retrieving a scratch context, otherwise another thread could still tear it down between the time it was created and the creation of the reader object. There are other shortcomings in GetSwiftScratchContext() that are documented, but not addressed, in this patch to make it easier to review.
1 parent 87ac257 commit b64d0a2

File tree

2 files changed

+69
-50
lines changed

2 files changed

+69
-50
lines changed

lldb/include/lldb/Core/SwiftScratchContextReader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class SwiftScratchContextReader {
5252
TypeSystemSwiftTypeRefForExpressions *m_ts;
5353

5454
public:
55-
SwiftScratchContextReader(std::shared_mutex &mutex,
55+
SwiftScratchContextReader(std::shared_lock<std::shared_mutex> &&lock,
5656
TypeSystemSwiftTypeRefForExpressions &ts);
5757
SwiftScratchContextReader(const SwiftScratchContextReader &) = delete;
5858
SwiftScratchContextReader(SwiftScratchContextReader &&other) = default;

lldb/source/Target/Target.cpp

Lines changed: 68 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2716,62 +2716,69 @@ llvm::Optional<SwiftScratchContextReader> Target::GetSwiftScratchContext(
27162716
}
27172717
}
27182718
}
2719-
2720-
auto get_or_create_fallback_context =
2721-
[&]() -> TypeSystemSwiftTypeRefForExpressions * {
2722-
ModuleLanguage idx = {lldb_module, lldb::eLanguageTypeSwift};
2723-
auto cached = m_scratch_typesystem_for_module.find(idx);
2724-
if (cached != m_scratch_typesystem_for_module.end()) {
2725-
auto *cached_ts =
2726-
llvm::cast<TypeSystemSwiftTypeRefForExpressions>(cached->second.get());
2727-
if (!cached_ts)
2728-
return nullptr;
2719+
2720+
auto get_cached_module_ts =
2721+
[&](Module *lldb_module) -> TypeSystemSwiftTypeRefForExpressions * {
2722+
ModuleLanguage key = {lldb_module, lldb::eLanguageTypeSwift};
2723+
auto cached = m_scratch_typesystem_for_module.find(key);
2724+
if (cached != m_scratch_typesystem_for_module.end())
2725+
return llvm::cast<TypeSystemSwiftTypeRefForExpressions>(cached->second.get());
2726+
return nullptr;
2727+
};
2728+
2729+
auto maybe_create_fallback_context = [&]() {
2730+
ModuleLanguage key = {lldb_module, lldb::eLanguageTypeSwift};
2731+
if (auto *cached_ts = get_cached_module_ts(lldb_module)) {
27292732
auto *cached_ast_ctx =
27302733
llvm::dyn_cast_or_null<SwiftASTContextForExpressions>(
27312734
cached_ts->GetSwiftASTContext());
27322735
if (cached_ast_ctx && cached_ast_ctx->HasFatalErrors() &&
27332736
!m_cant_make_scratch_type_system.count(lldb::eLanguageTypeSwift)) {
27342737
DisplayFallbackSwiftContextErrors(cached_ast_ctx);
27352738
// Try again.
2736-
m_scratch_typesystem_for_module.erase(cached);
2737-
return nullptr;
2739+
// FIXME: Shouldn't this continue rather than return?
2740+
m_scratch_typesystem_for_module.erase(key);
2741+
if (log)
2742+
log->Printf("erased module-wide scratch context with errors\n");
2743+
return;
27382744
}
27392745
if (log)
27402746
log->Printf("returned cached module-wide scratch context\n");
2741-
return cached_ts;
2747+
return;
27422748
}
27432749

27442750
if (!create_on_demand) {
27452751
if (log)
27462752
log->Printf("not allowed to create a new context\n");
2747-
return nullptr;
2753+
return;
27482754
}
27492755

2750-
// Call for its side effects of establishing the Swift scratch type system.
2756+
// Call for its side effects of establishing the Swift scratch type
2757+
// system.
27512758
auto type_system_or_err =
27522759
GetScratchTypeSystemForLanguage(eLanguageTypeSwift, false);
27532760
if (!type_system_or_err) {
27542761
llvm::consumeError(type_system_or_err.takeError());
2755-
return nullptr;
2762+
return;
27562763
}
27572764

27582765
auto &lock = GetSwiftScratchContextLock();
27592766
if (!lock.try_lock()) {
27602767
if (log)
27612768
log->Printf("couldn't acquire scratch context lock\n");
2762-
return nullptr;
2769+
return;
27632770
}
27642771
auto unlock = llvm::make_scope_exit([&lock] { lock.unlock(); });
27652772

2766-
// With the lock held, get the current scratch type system. This ensures the
2767-
// current instance is used even in the unlikely event it was changed during
2768-
// the brief window between the call to `GetScratchTypeSystemForLanguage`
2769-
// and taking the lock.
2773+
// With the lock held, get the current scratch type system. This ensures
2774+
// the current instance is used even in the unlikely event it was changed
2775+
// during the brief window between the call to
2776+
// `GetScratchTypeSystemForLanguage` and taking the lock.
27702777
type_system_or_err = m_scratch_type_system_map.GetTypeSystemForLanguage(
27712778
eLanguageTypeSwift, this, false);
27722779
if (!type_system_or_err) {
27732780
llvm::consumeError(type_system_or_err.takeError());
2774-
return nullptr;
2781+
return;
27752782
}
27762783

27772784
if (auto *global_scratch_ctx =
@@ -2785,41 +2792,52 @@ llvm::Optional<SwiftScratchContextReader> Target::GetSwiftScratchContext(
27852792
auto typesystem_sp = std::make_shared<TypeSystemSwiftTypeRefForExpressions>(
27862793
lldb::eLanguageTypeSwift, *this, *lldb_module);
27872794
typesystem_sp->GetSwiftASTContext();
2788-
m_scratch_typesystem_for_module.insert({idx, typesystem_sp});
2795+
m_scratch_typesystem_for_module.insert({key, typesystem_sp});
27892796
if (log)
27902797
log->Printf("created module-wide scratch context\n");
2791-
return typesystem_sp.get();
2798+
return;
27922799
};
27932800

2794-
TypeSystemSwiftTypeRefForExpressions *swift_scratch_ctx = nullptr;
2795-
if (lldb_module && m_use_scratch_typesystem_per_module)
2796-
swift_scratch_ctx = get_or_create_fallback_context();
2797-
if (!swift_scratch_ctx) {
2798-
if (log)
2799-
log->Printf("returned project-wide scratch context\n");
2801+
llvm::Optional<SwiftScratchContextReader> reader;
2802+
if (lldb_module && m_use_scratch_typesystem_per_module) {
2803+
maybe_create_fallback_context();
2804+
std::shared_lock<std::shared_mutex> lock(GetSwiftScratchContextLock());
2805+
if (auto *cached_ts = get_cached_module_ts(lldb_module)) {
2806+
reader = SwiftScratchContextReader(std::move(lock), *cached_ts);
2807+
if (log)
2808+
log->Printf("returned module-wide scratch context\n");
2809+
}
2810+
}
2811+
// FIXME: Don't return the project-wide context after requesting the
2812+
// module-wide one.
2813+
if (!reader) {
2814+
std::shared_lock<std::shared_mutex> lock(GetSwiftScratchContextLock());
28002815
auto type_system_or_err =
28012816
GetScratchTypeSystemForLanguage(eLanguageTypeSwift, create_on_demand);
2802-
if (type_system_or_err)
2803-
swift_scratch_ctx =
2804-
llvm::cast_or_null<TypeSystemSwiftTypeRefForExpressions>(
2805-
type_system_or_err->get());
2806-
else
2817+
if (type_system_or_err) {
2818+
if (auto *ts = llvm::cast_or_null<TypeSystemSwiftTypeRefForExpressions>(
2819+
type_system_or_err->get())) {
2820+
reader = SwiftScratchContextReader(std::move(lock), *ts);
2821+
if (log)
2822+
log->Printf("returned project-wide scratch context\n");
2823+
}
2824+
} else
28072825
llvm::consumeError(type_system_or_err.takeError());
28082826
}
28092827

2810-
StackFrameSP frame_sp = exe_scope.CalculateStackFrame();
2811-
if (frame_sp && frame_sp.get() && swift_scratch_ctx) {
2812-
SymbolContext sc =
2813-
frame_sp->GetSymbolContext(lldb::eSymbolContextEverything);
2814-
Status status = swift_scratch_ctx->PerformCompileUnitImports(sc);
2815-
if (status.Fail())
2816-
Debugger::ReportError(status.AsCString(), GetDebugger().GetID());
2828+
if (reader) {
2829+
// Perform compile unit imports.
2830+
assert(reader->get());
2831+
StackFrameSP frame_sp = exe_scope.CalculateStackFrame();
2832+
if (frame_sp && frame_sp.get()) {
2833+
SymbolContext sc =
2834+
frame_sp->GetSymbolContext(lldb::eSymbolContextEverything);
2835+
Status status = reader->get()->PerformCompileUnitImports(sc);
2836+
if (status.Fail())
2837+
Debugger::ReportError(status.AsCString(), GetDebugger().GetID());
2838+
}
28172839
}
2818-
2819-
if (!swift_scratch_ctx)
2820-
return llvm::None;
2821-
return SwiftScratchContextReader(GetSwiftScratchContextLock(),
2822-
*swift_scratch_ctx);
2840+
return reader;
28232841
}
28242842

28252843
static std::shared_mutex *
@@ -2833,8 +2851,9 @@ GetSwiftScratchContextMutex(const ExecutionContext *exe_ctx) {
28332851
}
28342852

28352853
SwiftScratchContextReader::SwiftScratchContextReader(
2836-
std::shared_mutex &mutex, TypeSystemSwiftTypeRefForExpressions &ts)
2837-
: m_lock(mutex), m_ts(&ts) {}
2854+
std::shared_lock<std::shared_mutex> &&lock,
2855+
TypeSystemSwiftTypeRefForExpressions &ts)
2856+
: m_lock(std::move(lock)), m_ts(&ts) {}
28382857

28392858
SwiftScratchContextLock::SwiftScratchContextLock(
28402859
const ExecutionContext *exe_ctx) {

0 commit comments

Comments
 (0)