Skip to content

Commit 427fb5c

Browse files
committed
[ORC] Track all dependencies on symbols that aren't Ready yet.
AsynchronousSymbolQuery tracks the symbols that it depends on in order to (1) detach the query in the event of a failure, and (2) report those dependencies to clients of the ExecutionSession::lookup method (via the RegisterDependencies argument). Previously we tracked only dependencies on symbols that didn't meet the required state (the only symbols that the query needs to be attached to), but this is insufficient to report all necessary dependencies to lookup clients. E.g. A lookup requiring SymbolState::Resolved where some matched symbol is already Resolved but not yet Emitted or Ready would result in the dependency on that symbol not being reported, which could result in illegal access in concurrent JIT setups. (This bug was discovered by @mikaoP on discord with a simple concurrent JIT setup). This patch tracks and reports all dependencies on symbols that aren't Ready yet, correcting the under-reporting issue. AsynchronousSymbolQuery::detach is updated to stop asserting that all depended-upon symbols have a query attached.
1 parent a4c3683 commit 427fb5c

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

llvm/lib/ExecutionEngine/Orc/Core.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,6 @@ Error JITDylib::resolve(MaterializationResponsibility &MR,
938938
auto &MI = MII->second;
939939
for (auto &Q : MI.takeQueriesMeeting(SymbolState::Resolved)) {
940940
Q->notifySymbolMetRequiredState(Name, ResolvedSym);
941-
Q->removeQueryDependence(*this, Name);
942941
if (Q->isComplete())
943942
CompletedQueries.insert(std::move(Q));
944943
}
@@ -1207,9 +1206,8 @@ void JITDylib::MaterializingInfo::removeQuery(
12071206
PendingQueries, [&Q](const std::shared_ptr<AsynchronousSymbolQuery> &V) {
12081207
return V.get() == &Q;
12091208
});
1210-
assert(I != PendingQueries.end() &&
1211-
"Query is not attached to this MaterializingInfo");
1212-
PendingQueries.erase(I);
1209+
if (I != PendingQueries.end())
1210+
PendingQueries.erase(I);
12131211
}
12141212

12151213
JITDylib::AsynchronousSymbolQueryList
@@ -2615,6 +2613,12 @@ void ExecutionSession::OL_completeLookup(
26152613
LLVM_DEBUG(dbgs()
26162614
<< "matched, symbol already in required state\n");
26172615
Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
2616+
2617+
// If this symbol is in anything other than the Ready state then
2618+
// we need to track the dependence.
2619+
if (SymI->second.getState() != SymbolState::Ready)
2620+
Q->addQueryDependence(JD, Name);
2621+
26182622
return true;
26192623
}
26202624

@@ -3165,7 +3169,6 @@ void ExecutionSession::IL_makeEDUEmitted(
31653169
Q->notifySymbolMetRequiredState(SymbolStringPtr(Sym), Entry.getSymbol());
31663170
if (Q->isComplete())
31673171
Queries.insert(Q);
3168-
Q->removeQueryDependence(JD, SymbolStringPtr(Sym));
31693172
}
31703173
}
31713174

llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,71 @@ TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) {
518518
<< "Self-dependency prevented symbol from being marked ready";
519519
}
520520

521+
TEST_F(CoreAPIsStandardTest, TestBasicQueryDependenciesReporting) {
522+
// Test that dependencies are reported as expected.
523+
524+
bool DependenciesCallbackRan = false;
525+
526+
std::unique_ptr<MaterializationResponsibility> FooR;
527+
std::unique_ptr<MaterializationResponsibility> BarR;
528+
529+
cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
530+
SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
531+
[&](std::unique_ptr<MaterializationResponsibility> R) {
532+
FooR = std::move(R);
533+
})));
534+
535+
cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
536+
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
537+
[&](std::unique_ptr<MaterializationResponsibility> R) {
538+
BarR = std::move(R);
539+
})));
540+
541+
cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
542+
SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
543+
[&](std::unique_ptr<MaterializationResponsibility> R) {
544+
cantFail(R->notifyResolved({{Baz, BazSym}}));
545+
cantFail(R->notifyEmitted({}));
546+
})));
547+
548+
// First issue a lookup for Foo and Bar so that we can put them
549+
// into the required states for the test lookup below.
550+
ES.lookup(
551+
LookupKind::Static, makeJITDylibSearchOrder(&JD),
552+
SymbolLookupSet({Foo, Bar}), SymbolState::Resolved,
553+
[](Expected<SymbolMap> Result) {
554+
EXPECT_THAT_EXPECTED(std::move(Result), Succeeded());
555+
},
556+
NoDependenciesToRegister);
557+
558+
cantFail(FooR->notifyResolved({{Foo, FooSym}}));
559+
cantFail(FooR->notifyEmitted({}));
560+
561+
cantFail(BarR->notifyResolved({{Bar, BarSym}}));
562+
563+
ES.lookup(
564+
LookupKind::Static, makeJITDylibSearchOrder(&JD),
565+
SymbolLookupSet({Foo, Bar, Baz}), SymbolState::Resolved,
566+
[](Expected<SymbolMap> Result) {
567+
EXPECT_THAT_EXPECTED(std::move(Result), Succeeded());
568+
},
569+
[&](const SymbolDependenceMap &Dependencies) {
570+
EXPECT_EQ(Dependencies.size(), 1U)
571+
<< "Expect dependencies on only one JITDylib";
572+
EXPECT_TRUE(Dependencies.count(&JD))
573+
<< "Expect dependencies on JD only";
574+
auto &Deps = Dependencies.begin()->second;
575+
EXPECT_EQ(Deps.size(), 2U);
576+
EXPECT_TRUE(Deps.count(Bar));
577+
EXPECT_TRUE(Deps.count(Baz));
578+
DependenciesCallbackRan = true;
579+
});
580+
581+
cantFail(BarR->notifyEmitted({}));
582+
583+
EXPECT_TRUE(DependenciesCallbackRan);
584+
}
585+
521586
TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
522587
// Test that a circular symbol dependency between three symbols in a JITDylib
523588
// does not prevent any symbol from becoming 'ready' once all symbols are

0 commit comments

Comments
 (0)