Instead of check each load and store instruction, we check the usage of the load instruction. Currently, there are four kinds of instruction that may use a load instruction as its argument: load, store, GEP and call instruction. We instrument these four kinds instruction to check there may be a null pointer dereference.

This commit is contained in:
Baozeng Ding 2013-08-08 17:18:21 +02:00 committed by sftnight
parent 6c734dd78c
commit 261bedbfe6
2 changed files with 70 additions and 56 deletions

View File

@ -19,6 +19,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/InstIterator.h"
@ -108,12 +109,12 @@ namespace cling {
runOnFunction(*F);
}
llvm::BasicBlock* NullDerefProtectionTransformer::getTrapBB() {
llvm::BasicBlock*
NullDerefProtectionTransformer::getTrapBB(llvm::BasicBlock* BB) {
llvm::Function* Fn = Inst->getParent()->getParent();
llvm::Module* Md = Fn->getParent();
llvm::LLVMContext& ctx = Fn->getContext();
llvm::BasicBlock::iterator PreInsertInst = Builder->GetInsertPoint();
FailBB = llvm::BasicBlock::Create(ctx, "FailBlock", Fn);
Builder->SetInsertPoint(FailBB);
@ -149,57 +150,35 @@ namespace cling {
llvm::Value* TrueVl = llvm::ConstantInt::get(ctx, llvm::APInt(1, 1));
llvm::Value* RetVl = CI;
llvm::ICmpInst*Cmp
llvm::ICmpInst* Cmp
= new llvm::ICmpInst(*FailBB, llvm::CmpInst::ICMP_EQ, RetVl, TrueVl, "");
llvm::BasicBlock *HandleBB = llvm::BasicBlock::Create(ctx,"HandleBlock", Fn);
llvm::BranchInst::Create(HandleBB, Inst->getParent(), Cmp, FailBB);
llvm::BranchInst::Create(HandleBB, BB, Cmp, FailBB);
llvm::ReturnInst::Create(Fn->getContext(), HandleBB);
Builder->SetInsertPoint(PreInsertInst);
return FailBB;
}
void NullDerefProtectionTransformer::instrumentLoadInst(llvm::LoadInst *LI) {
llvm::Value* Addr = LI->getOperand(0);
if(llvm::isa<llvm::GlobalVariable>(Addr))
return;
// Insert a cmp instruction before the "Inst" instruction to check whether the
// argument "Arg" for the instruction "Inst" is null or not.
void NullDerefProtectionTransformer::instrumentInst(
llvm::Instruction* Inst, llvm::Value* Arg) {
llvm::BasicBlock* OldBB = Inst->getParent();
// Insert a cmp instruction to check whether "Arg" is null or not.
llvm::ICmpInst* Cmp
= new llvm::ICmpInst(Inst, llvm::CmpInst::ICMP_EQ, Arg,
llvm::Constant::getNullValue(Arg->getType()), "");
llvm::PointerType* PTy = llvm::cast<llvm::PointerType>(Addr->getType());
llvm::Type* ElTy = PTy->getElementType();
if (!ElTy->isPointerTy()) {
llvm::BasicBlock* OldBB = LI->getParent();
llvm::ICmpInst* Cmp
= new llvm::ICmpInst(LI, llvm::CmpInst::ICMP_EQ, Addr,
llvm::Constant::getNullValue(Addr->getType()), "");
llvm::Instruction *Inst = Builder->GetInsertPoint();
llvm::BasicBlock *NewBB = OldBB->splitBasicBlock(Inst);
OldBB->getTerminator()->eraseFromParent();
llvm::BranchInst::Create(getTrapBB(), NewBB, Cmp, OldBB);
}
}
void NullDerefProtectionTransformer::instrumentStoreInst(llvm::StoreInst *SI){
llvm::Value* Addr = SI->getOperand(1);
if(llvm::isa<llvm::GlobalVariable>(Addr))
return;
llvm::PointerType* PTy = llvm::cast<llvm::PointerType>(Addr->getType());
llvm::Type* ElTy = PTy -> getElementType();
if (!ElTy->isPointerTy()) {
llvm::BasicBlock* OldBB = SI->getParent();
llvm::ICmpInst* Cmp
= new llvm::ICmpInst(SI, llvm::CmpInst::ICMP_EQ, Addr,
llvm::Constant::getNullValue(Addr->getType()), "");
llvm::Instruction* Inst = Builder->GetInsertPoint();
llvm::BasicBlock* NewBB = OldBB->splitBasicBlock(Inst);
OldBB->getTerminator()->eraseFromParent();
llvm::BranchInst::Create(getTrapBB(), NewBB, Cmp, OldBB);
}
// The block is splited into two blocks, "OldBB" and "NewBB", by the "Inst"
// instruction. After that split, "Inst" is at the start of "NewBB". Then
// insert a branch instruction at the end of "OldBB". If "Arg" is null,
// it will jump to "FailBB" created by "getTrapBB" function. Else, it means
// jump to the "NewBB".
llvm::BasicBlock* NewBB = OldBB->splitBasicBlock(Inst);
OldBB->getTerminator()->eraseFromParent();
llvm::BranchInst::Create(getTrapBB(NewBB), NewBB, Cmp, OldBB);
}
bool NullDerefProtectionTransformer::runOnFunction(llvm::Function &F) {
@ -209,21 +188,57 @@ namespace cling {
std::vector<llvm::Instruction*> WorkList;
for (llvm::inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
llvm::Instruction* I = &*i;
if (llvm::isa<llvm::LoadInst>(I) || llvm::isa<llvm::StoreInst>(I))
if (llvm::isa<llvm::LoadInst>(I))
WorkList.push_back(I);
}
}
for (std::vector<llvm::Instruction*>::iterator i = WorkList.begin(),
e = WorkList.end(); i != e; ++i) {
Inst = *i;
llvm::LoadInst* I = llvm::cast<llvm::LoadInst>(*i);
Builder->SetInsertPoint(Inst);
if (llvm::LoadInst* LI = llvm::dyn_cast<llvm::LoadInst>(Inst)) {
instrumentLoadInst(LI);
} else if (llvm::StoreInst* SI = llvm::dyn_cast<llvm::StoreInst>(Inst)) {
instrumentStoreInst(SI);
} else {
llvm_unreachable("unknown Instruction type");
// Find all the instructions that uses the instruction I.
for (llvm::Value::use_iterator UI = I->use_begin(), UE = I->use_end();
UI != UE; ++UI) {
// Check whether I is used as the first argument for a load instruction.
// If it is, then instrument the load instruction.
if (llvm::LoadInst* LI = llvm::dyn_cast<llvm::LoadInst>(*UI)) {
llvm::Value* Arg = LI->getOperand(0);
if (Arg == I)
instrumentInst(LI, Arg);
}
// Check whether I is used as the second argument for a store
// instruction. If it is, then instrument the store instruction.
else if (llvm::StoreInst* SI = llvm::dyn_cast<llvm::StoreInst>(*UI)) {
llvm::Value* Arg = SI->getOperand(1);
if (Arg == I)
instrumentInst(SI, Arg);
}
// Check whether I is used as the first argument for a GEP instruction.
// If it is, then instrument the GEP instruction.
else if (llvm::GetElementPtrInst* GEP = llvm::dyn_cast<
llvm::GetElementPtrInst>(*UI)) {
llvm::Value* Arg = GEP->getOperand(0);
if (Arg == I)
instrumentInst(GEP, Arg);
}
else {
// Check whether I is used as the first argument for a call instruction.
// If it is, then instrument the call instruction.
llvm::CallSite CS(*UI);
if (CS) {
llvm::CallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end();
if (i != e) {
llvm::Value *Arg = *i;
if (Arg == I)
instrumentInst(CS.getInstruction(), Arg);
}
}
}
}
}
return true;

View File

@ -35,9 +35,8 @@ namespace cling {
llvm::Instruction* Inst;
llvm::OwningPtr<clang::MangleContext> m_MangleCtx;
llvm::BasicBlock* getTrapBB();
void instrumentLoadInst(llvm::LoadInst* LI);
void instrumentStoreInst(llvm::StoreInst* SI);
llvm::BasicBlock* getTrapBB(llvm::BasicBlock* BB);
void instrumentInst(llvm::Instruction* Inst, llvm::Value* Arg);
bool runOnFunction(llvm::Function& F);
public: