Fix bug in exception table allocation (PR13678)

Patch by Michael Muller.

llvm-svn: 172214
This commit is contained in:
Eli Bendersky 2013-01-11 16:33:30 +00:00
parent f3a7087194
commit 738fbca845
2 changed files with 67 additions and 10 deletions

View File

@ -969,14 +969,24 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
SavedBufferBegin = BufferBegin;
SavedBufferEnd = BufferEnd;
SavedCurBufferPtr = CurBufferPtr;
uint8_t *FrameRegister;
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);
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;

View File

@ -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;
}