llvm.org GIT mirror llvm / 1a41a8e
[Orc][RuntimeDyld] Prevent duplicate calls to finalizeMemory on shared memory managers. Prior to this patch, recursive finalization (where finalization of one RuntimeDyld instance triggers finalization of another instance on which the first depends) could trigger memory access failures: When the inner (dependent) RuntimeDyld instance and its memory manager are finalized, memory allocated (but not yet relocated) by the outer instance is locked, and relocation in the outer instance fails with a memory access error. This patch adds a latch to the RuntimeDyld::MemoryManager base class that is checked by a new method: RuntimeDyld::finalizeWithMemoryManagerLocking, ensuring that shared memory managers are only finalized by the outermost RuntimeDyld instance. This allows ORC clients to supply the same memory manager to multiple calls to addModuleSet. In particular it enables the use of user-supplied memory managers with the CompileOnDemandLayer which must reuse the supplied memory manager for each function that is lazily compiled. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257263 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 3 years ago
6 changed file(s) with 121 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
107107
108108 void Finalize() override {
109109 State = Finalizing;
110 RTDyld->resolveRelocations();
111 RTDyld->registerEHFrames();
112 MemMgr->finalizeMemory();
110 RTDyld->finalizeWithMemoryManagerLocking();
113111 State = Finalized;
114112 }
115113
9494
9595 /// \brief Memory Management.
9696 class MemoryManager {
97 public:
97 friend class RuntimeDyld;
98 public:
99 MemoryManager() : FinalizationLocked(false) {}
98100 virtual ~MemoryManager() {}
99101
100102 /// Allocate a memory block of (at least) the given size suitable for
152154
153155 private:
154156 virtual void anchor();
157 bool FinalizationLocked;
155158 };
156159
157160 /// \brief Symbol resolution.
240243 this->ProcessAllSections = ProcessAllSections;
241244 }
242245
246 /// Perform all actions needed to make the code owned by this RuntimeDyld
247 /// instance executable:
248 ///
249 /// 1) Apply relocations.
250 /// 2) Register EH frames.
251 /// 3) Update memory permissions*.
252 ///
253 /// * Finalization is potentially recursive**, and the 3rd step will only be
254 /// applied by the outermost call to finalize. This allows different
255 /// RuntimeDyld instances to share a memory manager without the innermost
256 /// finalization locking the memory and causing relocation fixup errors in
257 /// outer instances.
258 ///
259 /// ** Recursive finalization occurs when one RuntimeDyld instances needs the
260 /// address of a symbol owned by some other instance in order to apply
261 /// relocations.
262 ///
263 void finalizeWithMemoryManagerLocking();
264
243265 private:
244266 // RuntimeDyldImpl is the actual class. RuntimeDyld is just the public
245267 // interface.
966966
967967 StringRef RuntimeDyld::getErrorString() { return Dyld->getErrorString(); }
968968
969 void RuntimeDyld::finalizeWithMemoryManagerLocking() {
970 bool MemoryFinalizationLocked = MemMgr.FinalizationLocked;
971 MemMgr.FinalizationLocked = true;
972 resolveRelocations();
973 registerEHFrames();
974 if (!MemoryFinalizationLocked) {
975 MemMgr.finalizeMemory();
976 MemMgr.FinalizationLocked = false;
977 }
978 }
979
969980 void RuntimeDyld::registerEHFrames() {
970981 if (Dyld)
971982 Dyld->registerEHFrames();
66 //
77 //===----------------------------------------------------------------------===//
88
9 #include "OrcTestCommon.h"
910 #include "llvm/ExecutionEngine/ExecutionEngine.h"
1011 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
1112 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
1920 using namespace llvm::orc;
2021
2122 namespace {
23
24 class ObjectLinkingLayerExecutionTest : public testing::Test,
25 public OrcExecutionTest {
26 };
2227
2328 TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
2429
9095 }
9196 }
9297
98
99 TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
100
101 if (!TM)
102 return;
103
104 class SectionMemoryManagerWrapper : public SectionMemoryManager {
105 public:
106 int FinalizationCount = 0;
107 bool finalizeMemory(std::string *ErrMsg = 0) override {
108 ++FinalizationCount;
109 return SectionMemoryManager::finalizeMemory(ErrMsg);
110 }
111 };
112
113 ObjectLinkingLayer<> ObjLayer;
114 SimpleCompiler Compile(*TM);
115
116 // Create a pair of modules that will trigger recursive finalization:
117 // Module 1:
118 // int bar() { return 42; }
119 // Module 2:
120 // int bar();
121 // int foo() { return bar(); }
122
123 ModuleBuilder MB1(getGlobalContext(), "", "dummy");
124 {
125 MB1.getModule()->setDataLayout(TM->createDataLayout());
126 Function *BarImpl = MB1.createFunctionDecl("bar");
127 BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
128 BarImpl);
129 IRBuilder<> Builder(BarEntry);
130 IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
131 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
132 Builder.CreateRet(FourtyTwo);
133 }
134
135 auto Obj1 = Compile(*MB1.getModule());
136 std::vector Obj1Set;
137 Obj1Set.push_back(Obj1.getBinary());
138
139 ModuleBuilder MB2(getGlobalContext(), "", "dummy");
140 {
141 MB2.getModule()->setDataLayout(TM->createDataLayout());
142 Function *BarDecl = MB2.createFunctionDecl("bar");
143 Function *FooImpl = MB2.createFunctionDecl("foo");
144 BasicBlock *FooEntry = BasicBlock::Create(getGlobalContext(), "entry",
145 FooImpl);
146 IRBuilder<> Builder(FooEntry);
147 Builder.CreateRet(Builder.CreateCall(BarDecl));
148 }
149 auto Obj2 = Compile(*MB2.getModule());
150 std::vector Obj2Set;
151 Obj2Set.push_back(Obj2.getBinary());
152
153 auto Resolver =
154 createLambdaResolver(
155 [&](const std::string &Name) {
156 if (auto Sym = ObjLayer.findSymbol(Name, true))
157 return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags());
158 return RuntimeDyld::SymbolInfo(nullptr);
159 },
160 [](const std::string &Name) {
161 return RuntimeDyld::SymbolInfo(nullptr);
162 });
163
164 SectionMemoryManagerWrapper SMMW;
165 ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &*Resolver);
166 auto H = ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &*Resolver);
167 ObjLayer.emitAndFinalize(H);
168
169 // Finalization of module 2 should trigger finalization of module 1.
170 // Verify that finalize on SMMW is only called once.
171 EXPECT_EQ(SMMW.FinalizationCount, 1)
172 << "Extra call to finalize";
93173 }
174
175 }
1818
1919 ModuleBuilder::ModuleBuilder(LLVMContext &Context, StringRef Triple,
2020 StringRef Name)
21 : M(new Module(Name, Context)),
22 Builder(Context) {
23 M->setTargetTriple(Triple);
21 : M(new Module(Name, Context)) {
22 if (Triple != "")
23 M->setTargetTriple(Triple);
2424 }
1919 #include "llvm/IR/LLVMContext.h"
2020 #include "llvm/IR/Module.h"
2121 #include "llvm/IR/TypeBuilder.h"
22 #include "llvm/Object/ObjectFile.h"
2223 #include "llvm/ExecutionEngine/ExecutionEngine.h"
2324 #include "llvm/ExecutionEngine/Orc/JITSymbol.h"
2425 #include "llvm/Support/TargetSelect.h"
7374
7475 private:
7576 std::unique_ptr M;
76 IRBuilder<> Builder;
7777 };
7878
7979 // Dummy struct type.