Instruction *AddressSanitizer::generateCrashCode( IRBuilder<> &IRB, Value *Addr, bool IsWrite, uint32_t TypeSize) { // IsWrite and TypeSize are encoded in the function name. std::string FunctionName = std::string(kAsanReportErrorTemplate) + (IsWrite ? "store" : "load") + itostr(TypeSize / 8); Value *ReportWarningFunc = CurrentModule->getOrInsertFunction( FunctionName, IRB.getVoidTy(), IntptrTy, NULL); CallInst *Call = IRB.CreateCall(ReportWarningFunc, Addr); Call->setDoesNotReturn(); return Call; }
static InstTransResult doCallPC(InstPtr ip, BasicBlock *&b, VA tgtAddr) { Module *M = b->getParent()->getParent(); Function *ourF = b->getParent(); //insert a call to the call function //this function will be a translated function that we emit, so we should //be able to look it up in our module. std::string fname = "sub_"+to_string<VA>(tgtAddr, std::hex); Function *F = M->getFunction(fname); TASSERT( F != NULL, "Could not find function: " + fname ); writeFakeReturnAddr(b); //we need to wrap up our current context writeLocalsToContext(b, 32, ABICallStore); //make the call, the only argument should be our parents arguments TASSERT(ourF->arg_size() == 1, ""); std::vector<Value*> subArgs; subArgs.push_back(ourF->arg_begin()); CallInst *c = CallInst::Create(F, subArgs, "", b); c->setCallingConv(F->getCallingConv()); if ( ip->has_local_noreturn() ) { // noreturn functions just hit unreachable std::cout << __FUNCTION__ << ": Adding Unreachable Instruction to local noreturn" << std::endl; c->setDoesNotReturn(); c->setTailCall(); Value *unreachable = new UnreachableInst(b->getContext(), b); return EndBlock; } //spill our context back writeContextToLocals(b, 32, ABIRetSpill); //and we can continue to run the old code return ContinueBlock; }
/// getTrapBB - create a basic block that traps. All overflowing conditions /// branch to this block. There's only one trap block per function. BasicBlock *BoundsChecking::getTrapBB() { if (TrapBB && SingleTrapBB) return TrapBB; Function *Fn = Inst->getParent()->getParent(); BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint(); TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); Builder->SetInsertPoint(TrapBB); llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap); CallInst *TrapCall = Builder->CreateCall(F); TrapCall->setDoesNotReturn(); TrapCall->setDoesNotThrow(); TrapCall->setDebugLoc(Inst->getDebugLoc()); Builder->CreateUnreachable(); Builder->SetInsertPoint(PrevInsertPoint); return TrapBB; }
static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI, ScalarEvolution &SE) { const DataLayout &DL = F.getParent()->getDataLayout(); ObjectSizeOffsetEvaluator ObjSizeEval(DL, &TLI, F.getContext(), /*RoundToAlign=*/true); // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory // touching instructions SmallVector<std::pair<Instruction *, Value *>, 4> TrapInfo; for (Instruction &I : instructions(F)) { Value *Or = nullptr; BuilderTy IRB(I.getParent(), BasicBlock::iterator(&I), TargetFolder(DL)); if (LoadInst *LI = dyn_cast<LoadInst>(&I)) { Or = getBoundsCheckCond(LI->getPointerOperand(), LI, DL, TLI, ObjSizeEval, IRB, SE); } else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) { Or = getBoundsCheckCond(SI->getPointerOperand(), SI->getValueOperand(), DL, TLI, ObjSizeEval, IRB, SE); } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(&I)) { Or = getBoundsCheckCond(AI->getPointerOperand(), AI->getCompareOperand(), DL, TLI, ObjSizeEval, IRB, SE); } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(&I)) { Or = getBoundsCheckCond(AI->getPointerOperand(), AI->getValOperand(), DL, TLI, ObjSizeEval, IRB, SE); } if (Or) TrapInfo.push_back(std::make_pair(&I, Or)); } // Create a trapping basic block on demand using a callback. Depending on // flags, this will either create a single block for the entire function or // will create a fresh block every time it is called. BasicBlock *TrapBB = nullptr; auto GetTrapBB = [&TrapBB](BuilderTy &IRB) { if (TrapBB && SingleTrapBB) return TrapBB; Function *Fn = IRB.GetInsertBlock()->getParent(); // FIXME: This debug location doesn't make a lot of sense in the // `SingleTrapBB` case. auto DebugLoc = IRB.getCurrentDebugLocation(); IRBuilder<>::InsertPointGuard Guard(IRB); TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); IRB.SetInsertPoint(TrapBB); auto *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap); CallInst *TrapCall = IRB.CreateCall(F, {}); TrapCall->setDoesNotReturn(); TrapCall->setDoesNotThrow(); TrapCall->setDebugLoc(DebugLoc); IRB.CreateUnreachable(); return TrapBB; }; // Add the checks. for (const auto &Entry : TrapInfo) { Instruction *Inst = Entry.first; BuilderTy IRB(Inst->getParent(), BasicBlock::iterator(Inst), TargetFolder(DL)); insertBoundsCheck(Entry.second, IRB, GetTrapBB); } return !TrapInfo.empty(); }
static InstTransResult doCallPCExtern(BasicBlock *&b, std::string target, bool esp_adjust = false) { Module *M = b->getParent()->getParent(); //write it into the location pointer to by ESP-4 Value *espOld = R_READ<32>(b, X86::ESP); //Value *espSub = // BinaryOperator::CreateSub(espOld, CONST_V<32>(b, 4), "", b); //M_WRITE_0<32>(b, espSub, CONST_V<32>(b, 0)); //R_WRITE<32>(b, X86::ESP, espSub); //write the local values into the context register //for now, we will stop doing this because we are not calling a wrapper //that meaningfully understands the context structure //writeLocalsToContext(b, 32); //lookup the function in the module Function *externFunction = M->getFunction(target); TASSERT(externFunction != NULL, "Coult not find external function: "+target); FunctionType *externFunctionTy = externFunction->getFunctionType(); Type *rType = externFunction->getReturnType(); int paramCount = externFunctionTy->getNumParams(); //now we need to do a series of reads off the stack, essentially //a series of POPs but without writing anything back to ESP Value *baseEspVal=NULL; std::vector<Value *> arguments; // in fastcall, the first two params are passed via register // only need to adjust stack if there are more than two args if( externFunction->getCallingConv() == CallingConv::X86_FastCall) { Function::ArgumentListType::iterator it = externFunction->getArgumentList().begin(); Function::ArgumentListType::iterator end = externFunction->getArgumentList().end(); AttrBuilder B; B.addAttribute(Attribute::InReg); if(paramCount && it != end) { Value *r_ecx = R_READ<32>(b, X86::ECX); arguments.push_back(r_ecx); --paramCount; // set argument 1's attribute: make it in a register it->addAttr(AttributeSet::get(it->getContext(), 1, B)); ++it; } if(paramCount && it != end) { Value *r_edx = R_READ<32>(b, X86::EDX); arguments.push_back(r_edx); --paramCount; // set argument 2's attribute: make it in a register it->addAttr(AttributeSet::get(it->getContext(), 2, B)); ++it; } } if( paramCount ) { baseEspVal = R_READ<32>(b, X86::ESP); if(esp_adjust) { baseEspVal = BinaryOperator::CreateAdd(baseEspVal, CONST_V<32>(b, 4), "", b); } } for( int i = 0; i < paramCount; i++ ) { Value *vFromStack = M_READ_0<32>(b, baseEspVal); arguments.push_back(vFromStack); if( i+1 != paramCount ) { baseEspVal = BinaryOperator::CreateAdd(baseEspVal, CONST_V<32>(b, 4), "", b); } } CallInst *callR = CallInst::Create(externFunction, arguments, "", b); callR->setCallingConv(externFunction->getCallingConv()); noAliasMCSemaScope(callR); if ( externFunction->doesNotReturn() ) { // noreturn functions just hit unreachable std::cout << __FUNCTION__ << ": Adding Unreachable Instruction" << std::endl; callR->setDoesNotReturn(); callR->setTailCall(); Value *unreachable = new UnreachableInst(b->getContext(), b); return EndBlock; } //then, put the registers back into the locals //see above //writeContextToLocals(b, 32); // we returned from an extern: assume it cleared the direction flag // which is standard for MS calling conventions // F_CLEAR(b, DF); //if our convention says to keep the call result alive then do it //really, we could always keep the call result alive... if( rType == Type::getInt32Ty(M->getContext()) ) { R_WRITE<32>(b, X86::EAX, callR); } // stdcall and fastcall: callee changed ESP; adjust // REG_ESP accordingly if( externFunction->getCallingConv() == CallingConv::X86_StdCall || externFunction->getCallingConv() == CallingConv::X86_FastCall) { Value *ESP_adjust = CONST_V<32>(b, 4*paramCount); Value *espFix = BinaryOperator::CreateAdd(espOld, ESP_adjust, "", b); R_WRITE<32>(b, X86::ESP, espFix); } return ContinueBlock; }
virtual bool runOnFunction(Function &F) { DEBUG(errs() << "Running on " << F.getName() << "\n"); DEBUG(F.dump()); Changed = false; BaseMap.clear(); BoundsMap.clear(); AbrtBB = 0; valid = true; if (!rootNode) { rootNode = getAnalysis<CallGraph>().getRoot(); // No recursive functions for now. // In the future we may insert runtime checks for stack depth. for (scc_iterator<CallGraphNode*> SCCI = scc_begin(rootNode), E = scc_end(rootNode); SCCI != E; ++SCCI) { const std::vector<CallGraphNode*> &nextSCC = *SCCI; if (nextSCC.size() > 1 || SCCI.hasLoop()) { errs() << "INVALID: Recursion detected, callgraph SCC components: "; for (std::vector<CallGraphNode*>::const_iterator I = nextSCC.begin(), E = nextSCC.end(); I != E; ++I) { Function *FF = (*I)->getFunction(); if (FF) { errs() << FF->getName() << ", "; badFunctions.insert(FF); } } if (SCCI.hasLoop()) errs() << "(self-loop)"; errs() << "\n"; } // we could also have recursion via function pointers, but we don't // allow calls to unknown functions, see runOnFunction() below } } BasicBlock::iterator It = F.getEntryBlock().begin(); while (isa<AllocaInst>(It) || isa<PHINode>(It)) ++It; EP = &*It; TD = &getAnalysis<TargetData>(); SE = &getAnalysis<ScalarEvolution>(); PT = &getAnalysis<PointerTracking>(); DT = &getAnalysis<DominatorTree>(); std::vector<Instruction*> insns; BasicBlock *LastBB = 0; bool skip = false; for (inst_iterator I=inst_begin(F),E=inst_end(F); I != E;++I) { Instruction *II = &*I; if (II->getParent() != LastBB) { LastBB = II->getParent(); skip = DT->getNode(LastBB) == 0; } if (skip) continue; if (isa<LoadInst>(II) || isa<StoreInst>(II) || isa<MemIntrinsic>(II)) insns.push_back(II); if (CallInst *CI = dyn_cast<CallInst>(II)) { Value *V = CI->getCalledValue()->stripPointerCasts(); Function *F = dyn_cast<Function>(V); if (!F) { printLocation(CI, true); errs() << "Could not determine call target\n"; valid = 0; continue; } if (!F->isDeclaration()) continue; insns.push_back(CI); } } while (!insns.empty()) { Instruction *II = insns.back(); insns.pop_back(); DEBUG(dbgs() << "checking " << *II << "\n"); if (LoadInst *LI = dyn_cast<LoadInst>(II)) { const Type *Ty = LI->getType(); valid &= validateAccess(LI->getPointerOperand(), TD->getTypeAllocSize(Ty), LI); } else if (StoreInst *SI = dyn_cast<StoreInst>(II)) { const Type *Ty = SI->getOperand(0)->getType(); valid &= validateAccess(SI->getPointerOperand(), TD->getTypeAllocSize(Ty), SI); } else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(II)) { valid &= validateAccess(MI->getDest(), MI->getLength(), MI); if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI)) { valid &= validateAccess(MTI->getSource(), MI->getLength(), MI); } } else if (CallInst *CI = dyn_cast<CallInst>(II)) { Value *V = CI->getCalledValue()->stripPointerCasts(); Function *F = cast<Function>(V); const FunctionType *FTy = F->getFunctionType(); CallSite CS(CI); if (F->getName().equals("memcmp") && FTy->getNumParams() == 3) { valid &= validateAccess(CS.getArgument(0), CS.getArgument(2), CI); valid &= validateAccess(CS.getArgument(1), CS.getArgument(2), CI); continue; } unsigned i; #ifdef CLAMBC_COMPILER i = 0; #else i = 1;// skip hidden ctx* #endif for (;i<FTy->getNumParams();i++) { if (isa<PointerType>(FTy->getParamType(i))) { Value *Ptr = CS.getArgument(i); if (i+1 >= FTy->getNumParams()) { printLocation(CI, false); errs() << "Call to external function with pointer parameter last cannot be analyzed\n"; errs() << *CI << "\n"; valid = 0; break; } Value *Size = CS.getArgument(i+1); if (!Size->getType()->isIntegerTy()) { printLocation(CI, false); errs() << "Pointer argument must be followed by integer argument representing its size\n"; errs() << *CI << "\n"; valid = 0; break; } valid &= validateAccess(Ptr, Size, CI); } } } } if (badFunctions.count(&F)) valid = 0; if (!valid) { DEBUG(F.dump()); ClamBCModule::stop("Verification found errors!", &F); // replace function with call to abort std::vector<const Type*>args; FunctionType* abrtTy = FunctionType::get( Type::getVoidTy(F.getContext()),args,false); Constant *func_abort = F.getParent()->getOrInsertFunction("abort", abrtTy); BasicBlock *BB = &F.getEntryBlock(); Instruction *I = &*BB->begin(); Instruction *UI = new UnreachableInst(F.getContext(), I); CallInst *AbrtC = CallInst::Create(func_abort, "", UI); AbrtC->setCallingConv(CallingConv::C); AbrtC->setTailCall(true); AbrtC->setDoesNotReturn(true); AbrtC->setDoesNotThrow(true); // remove all instructions from entry BasicBlock::iterator BBI = I, BBE=BB->end(); while (BBI != BBE) { if (!BBI->use_empty()) BBI->replaceAllUsesWith(UndefValue::get(BBI->getType())); BB->getInstList().erase(BBI++); } } return Changed; }