diff options
-rw-r--r-- | lib/ExecutionEngine/JIT/JITEmitter.cpp | 26 | ||||
-rw-r--r-- | unittests/ExecutionEngine/JIT/JITTest.cpp | 53 |
2 files changed, 68 insertions, 11 deletions
diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 6fd4df4..c273876 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -969,14 +969,24 @@ bool JITEmitter::finishFunction(MachineFunction &F) { SavedBufferBegin = BufferBegin; SavedBufferEnd = BufferEnd; SavedCurBufferPtr = CurBufferPtr; - - BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(), - ActualSize); - BufferEnd = BufferBegin+ActualSize; - EmittedFunctions[F.getFunction()].ExceptionTable = BufferBegin; - uint8_t *EhStart; - uint8_t *FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd, - EhStart); + uint8_t *FrameRegister; + + while (true) { + BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(), + ActualSize); + BufferEnd = BufferBegin+ActualSize; + EmittedFunctions[F.getFunction()].ExceptionTable = BufferBegin; + uint8_t *EhStart; + FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd, EhStart); + + // If the buffer was large enough to hold the table then we are done. + if (CurBufferPtr != BufferEnd) + break; + + // Try again with twice as much space. + ActualSize = (CurBufferPtr - BufferBegin) * 2; + MemMgr->deallocateExceptionTable(BufferBegin); + } MemMgr->endExceptionTable(F.getFunction(), BufferBegin, CurBufferPtr, FrameRegister); BufferBegin = SavedBufferBegin; diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index 0a9ee82..30dadc9 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -161,7 +161,7 @@ public: uintptr_t ActualSizeResult; }; std::vector<StartExceptionTableCall> startExceptionTableCalls; - virtual uint8_t* startExceptionTable(const Function* F, + virtual uint8_t *startExceptionTable(const Function *F, uintptr_t &ActualSize) { uintptr_t InitialActualSize = ActualSize; uint8_t *Result = Base->startExceptionTable(F, ActualSize); @@ -203,14 +203,21 @@ bool LoadAssemblyInto(Module *M, const char *assembly) { class JITTest : public testing::Test { protected: + virtual RecordingJITMemoryManager *createMemoryManager() { + return new RecordingJITMemoryManager; + } + virtual void SetUp() { M = new Module("<main>", Context); - RJMM = new RecordingJITMemoryManager; + RJMM = createMemoryManager(); RJMM->setPoisonMemory(true); std::string Error; + TargetOptions Options; + Options.JITExceptionHandling = true; TheJIT.reset(EngineBuilder(M).setEngineKind(EngineKind::JIT) .setJITMemoryManager(RJMM) - .setErrorStr(&Error).create()); + .setErrorStr(&Error) + .setTargetOptions(Options).create()); ASSERT_TRUE(TheJIT.get() != NULL) << Error; } @@ -297,6 +304,46 @@ TEST(JIT, GlobalInFunction) { #endif // !defined(__arm__) && !defined(__powerpc__) +// Regression test for a bug. The JITEmitter wasn't checking to verify that +// it hadn't run out of space while generating the DWARF exception information +// for an emitted function. + +class ExceptionMemoryManagerMock : public RecordingJITMemoryManager { + public: + virtual uint8_t *startExceptionTable(const Function *F, + uintptr_t &ActualSize) { + // force an insufficient size the first time through. + bool ChangeActualSize = false; + if (ActualSize == 0) + ChangeActualSize = true;; + uint8_t *result = + RecordingJITMemoryManager::startExceptionTable(F, ActualSize); + if (ChangeActualSize) + ActualSize = 1; + return result; + } +}; + +class JITExceptionMemoryTest : public JITTest { + protected: + virtual RecordingJITMemoryManager *createMemoryManager() { + return new ExceptionMemoryManagerMock; + } +}; + +TEST_F(JITExceptionMemoryTest, ExceptionTableOverflow) { + Function *F = Function::Create(TypeBuilder<void(void), false>::get(Context), + Function::ExternalLinkage, + "func1", M); + BasicBlock *Block = BasicBlock::Create(Context, "block", F); + IRBuilder<> Builder(Block); + Builder.CreateRetVoid(); + TheJIT->getPointerToFunction(F); + ASSERT_TRUE(RJMM->startExceptionTableCalls.size() == 2); + ASSERT_TRUE(RJMM->deallocateExceptionTableCalls.size() == 1); + ASSERT_TRUE(RJMM->endExceptionTableCalls.size() == 1); +} + int PlusOne(int arg) { return arg + 1; } |