void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Get the method type. const FunctionProtoType *FnType = MCE->getCallee()->getType()->getAs<FunctionProtoType>(); assert(FnType && "Method type not available"); // Evaluate explicit arguments with a worklist. ExplodedNodeSet ArgsEvaluated; EvalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, ArgsEvaluated); // Evaluate the implicit object argument. ExplodedNodeSet AllArgsEvaluated; const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); if (!ME) return; Expr *ObjArgExpr = ME->getBase(); for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), E = ArgsEvaluated.end(); I != E; ++I) { if (ME->isArrow()) Visit(ObjArgExpr, *I, AllArgsEvaluated); else VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); } const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); assert(MD && "not a CXXMethodDecl?"); if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) // FIXME: conservative method call evaluation. return; const StackFrameContext *SFC = AMgr.getStackFrame(MD, Pred->getLocationContext(), MCE, Builder->getBlock(), Builder->getIndex()); const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); CallEnter Loc(MCE, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), E = AllArgsEvaluated.end(); I != E; ++I) { // Set up 'this' region. const GRState *state = GetState(*I); state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); ExplodedNode *N = Builder->generateNode(Loc, state, *I); if (N) Dst.Add(N); } }
void ExprEngine::evalCallee(const CallExpr *callExpr, const ExplodedNodeSet &src, ExplodedNodeSet &dest) { const Expr *callee = 0; switch (callExpr->getStmtClass()) { case Stmt::CXXMemberCallExprClass: { // Evaluate the implicit object argument that is the recipient of the // call. callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument(); // FIXME: handle member pointers. if (!callee) return; break; } default: { callee = callExpr->getCallee()->IgnoreParens(); break; } } for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i) Visit(callee, *i, dest); }
void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE, const FunctionProtoType *FnType, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool FstArgAsLValue) { llvm::SmallVector<CallExprWLItem, 20> WorkList; WorkList.reserve(AE - AI); WorkList.push_back(CallExprWLItem(AI, Pred)); while (!WorkList.empty()) { CallExprWLItem Item = WorkList.back(); WorkList.pop_back(); if (Item.I == AE) { Dst.insert(Item.N); continue; } // Evaluate the argument. ExplodedNodeSet Tmp; if (FstArgAsLValue) { FstArgAsLValue = false; } Visit(*Item.I, Item.N, Tmp); ++(Item.I); for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) WorkList.push_back(CallExprWLItem(Item.I, *NI)); } }
void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, const Expr *ThisExpr, ExplodedNode *Pred, ExplodedNodeSet &Src, ExplodedNodeSet &Dst) { // Allow checkers to pre-visit the member call. ExplodedNodeSet PreVisitChecks; CheckerVisit(MCE, PreVisitChecks, Src, PreVisitStmtCallback); if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) { // FIXME: conservative method call evaluation. CheckerVisit(MCE, Dst, PreVisitChecks, PostVisitStmtCallback); return; } const StackFrameContext *SFC = AMgr.getStackFrame(MD, Pred->getLocationContext(), MCE, Builder->getBlock(), Builder->getIndex()); const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); CallEnter Loc(MCE, SFC, Pred->getLocationContext()); for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(), E = PreVisitChecks.end(); I != E; ++I) { // Set up 'this' region. const GRState *state = GetState(*I); state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr)); Dst.Add(Builder->generateNode(Loc, state, *I)); } }
void CoreEngine::enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx) { for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) { enqueueStmtNode(*I, Block, Idx); } }
void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Get the method type. const FunctionProtoType *FnType = MCE->getCallee()->getType()->getAs<FunctionProtoType>(); assert(FnType && "Method type not available"); // Evaluate explicit arguments with a worklist. ExplodedNodeSet argsEvaluated; evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated); // Evaluate the implicit object argument. ExplodedNodeSet AllargsEvaluated; const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); if (!ME) return; Expr *ObjArgExpr = ME->getBase(); for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), E = argsEvaluated.end(); I != E; ++I) { Visit(ObjArgExpr, *I, AllargsEvaluated); } // Now evaluate the call itself. const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); assert(MD && "not a CXXMethodDecl?"); evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst); }
void GRExprEngine::EvalArguments(ConstExprIterator AI, ConstExprIterator AE, const FunctionProtoType *FnType, ExplodedNode *Pred, ExplodedNodeSet &Dst) { llvm::SmallVector<CallExprWLItem, 20> WorkList; WorkList.reserve(AE - AI); WorkList.push_back(CallExprWLItem(AI, Pred)); while (!WorkList.empty()) { CallExprWLItem Item = WorkList.back(); WorkList.pop_back(); if (Item.I == AE) { Dst.insert(Item.N); continue; } ExplodedNodeSet Tmp; const unsigned ParamIdx = Item.I - AI; bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType() : false; if (VisitAsLvalue) VisitLValue(*Item.I, Item.N, Tmp); else Visit(*Item.I, Item.N, Tmp); ++(Item.I); for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) WorkList.push_back(CallExprWLItem(Item.I, *NI)); } }
void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CXXConstructorCall &Call) { const CXXConstructExpr *CtorExpr = Call.getOriginExpr(); assert(CtorExpr->getConstructor()->isCopyOrMoveConstructor()); assert(CtorExpr->getConstructor()->isTrivial()); SVal ThisVal = Call.getCXXThisVal(); const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; Bldr.takeNodes(Pred); SVal V = Call.getArgSVal(0); // Make sure the value being copied is not unknown. if (const Loc *L = dyn_cast<Loc>(&V)) V = Pred->getState()->getSVal(*L); evalBind(Dst, CtorExpr, Pred, ThisVal, V, true); PostStmt PS(CtorExpr, LCtx); for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); State = bindReturnValue(Call, LCtx, State); Bldr.generateNode(PS, State, *I); } }
void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &dst) { // Perform the previsit of the CallExpr. ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this); // Get the call in its initial state. We use this as a template to perform // all the checks. CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<> CallTemplate = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext()); // Evaluate the function call. We try each of the checkers // to see if the can evaluate the function call. ExplodedNodeSet dstCallEvaluated; for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I != E; ++I) { evalCall(dstCallEvaluated, *I, *CallTemplate); } // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. // Note that if the call was inlined, dstCallEvaluated will be empty. // The post-CallExpr check will occur in processCallExit. getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, *this); }
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: static variables may have an initializer, but the second // time a function is called those values may not be current. // This may need to be reflected in the CFG. // Assumption: The CFG has one DeclStmt per Decl. const Decl *D = *DS->decl_begin(); if (!D || !isa<VarDecl>(D)) { //TODO:AZ: remove explicit insertion after refactoring is done. Dst.insert(Pred); return; } // FIXME: all pre/post visits should eventually be handled by ::Visit(). ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); const VarDecl *VD = dyn_cast<VarDecl>(D); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { ExplodedNode *N = *I; const ProgramState *state = N->getState(); // Decls without InitExpr are not initialized explicitly. const LocationContext *LC = N->getLocationContext(); if (const Expr *InitEx = VD->getInit()) { SVal InitVal = state->getSVal(InitEx, Pred->getLocationContext()); // We bound the temp obj region to the CXXConstructExpr. Now recover // the lazy compound value when the variable is not a reference. if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() && !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){ InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion()); assert(isa<nonloc::LazyCompoundVal>(InitVal)); } // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. if (InitVal.isUnknown()) { InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, currentBuilderContext->getCurrentBlockCount()); } B.takeNodes(N); ExplodedNodeSet Dst2; evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true); B.addNodes(Dst2); } else { B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC))); } } }
// FIXME: This is the sort of code that should eventually live in a Core // checker rather than as a special case in ExprEngine. void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &Call) { SVal ThisVal; bool AlwaysReturnsLValue; const CXXRecordDecl *ThisRD = nullptr; if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { assert(Ctor->getDecl()->isTrivial()); assert(Ctor->getDecl()->isCopyOrMoveConstructor()); ThisVal = Ctor->getCXXThisVal(); ThisRD = Ctor->getDecl()->getParent(); AlwaysReturnsLValue = false; } else { assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial()); assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() == OO_Equal); ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal(); ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent(); AlwaysReturnsLValue = true; } assert(ThisRD); if (ThisRD->isEmpty()) { // Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal // and bind it and RegionStore would think that the actual value // in this region at this offset is unknown. return; } const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; Bldr.takeNodes(Pred); SVal V = Call.getArgSVal(0); // If the value being copied is not unknown, load from its location to get // an aggregate rvalue. if (Optional<Loc> L = V.getAs<Loc>()) V = Pred->getState()->getSVal(*L); else assert(V.isUnknownOrUndef()); const Expr *CallExpr = Call.getOriginExpr(); evalBind(Dst, CallExpr, Pred, ThisVal, V, true); PostStmt PS(CallExpr, LCtx); for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); if (AlwaysReturnsLValue) State = State->BindExpr(CallExpr, LCtx, ThisVal); else State = bindReturnValue(Call, LCtx, State); Bldr.generateNode(PS, State, *I); } }
void GRExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,ExplodedNodeSet &Dst) { // Should do more checking. ExplodedNodeSet ArgEvaluated; Visit(CDE->getArgument(), Pred, ArgEvaluated); for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(), E = ArgEvaluated.end(); I != E; ++I) { const GRState *state = GetState(*I); MakeNode(Dst, CDE, *I, state); } }
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Should do more checking. ExplodedNodeSet Argevaluated; Visit(CDE->getArgument(), Pred, Argevaluated); StmtNodeBuilder Bldr(Argevaluated, Dst, *currentBuilderContext); for (ExplodedNodeSet::iterator I = Argevaluated.begin(), E = Argevaluated.end(); I != E; ++I) { const ProgramState *state = (*I)->getState(); Bldr.generateNode(CDE, *I, state); } }
void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &dst) { // Perform the previsit of the CallExpr. ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this); // Get the callee kind. CallEventKind K = classifyCallExpr(CE); // Evaluate the function call. We try each of the checkers // to see if the can evaluate the function call. ExplodedNodeSet dstCallEvaluated; for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); const LocationContext *LCtx = (*I)->getLocationContext(); // Evaluate the call. switch (K) { case CE_Function: { FunctionCall Call(CE, State, LCtx); evalCall(dstCallEvaluated, *I, Call); break; } case CE_CXXMember: { CXXMemberCall Call(cast<CXXMemberCallExpr>(CE), State, LCtx); evalCall(dstCallEvaluated, *I, Call); break; } case CE_CXXMemberOperator: { CXXMemberOperatorCall Call(cast<CXXOperatorCallExpr>(CE), State, LCtx); evalCall(dstCallEvaluated, *I, Call); break; } case CE_Block: { BlockCall Call(CE, State, LCtx); evalCall(dstCallEvaluated, *I, Call); break; } default: llvm_unreachable("Non-CallExpr CallEventKind"); } } // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. // Note that if the call was inlined, dstCallEvaluated will be empty. // The post-CallExpr check will occur in processCallExit. getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, *this); }
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this); StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx); if (RS->getRetValue()) { for (ExplodedNodeSet::iterator it = dstPreVisit.begin(), ei = dstPreVisit.end(); it != ei; ++it) { B.generateNode(RS, *it, (*it)->getState()); } } }
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (!Dest) Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E, Pred->getLocationContext()); if (E->isElidable()) { VisitAggExpr(E->getArg(0), Dest, Pred, Dst); // FIXME: this is here to force propogation if VisitAggExpr doesn't if (Dst.empty()) Dst.Add(Pred); return; } const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) // FIXME: invalidate the object. return; // Evaluate other arguments. ExplodedNodeSet argsEvaluated; const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); // The callee stack frame context used to create the 'this' parameter region. const StackFrameContext *SFC = AMgr.getStackFrame(CD, Pred->getLocationContext(), E, Builder->getBlock(), Builder->getIndex()); const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(), SFC); CallEnter Loc(E, SFC, Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), NE = argsEvaluated.end(); NI != NE; ++NI) { const GRState *state = GetState(*NI); // Setup 'this' region, so that the ctor is evaluated on the object pointed // by 'Dest'. state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); ExplodedNode *N = Builder->generateNode(Loc, state, Pred); if (N) Dst.Add(N); } }
void ExprEngine::processCallExit(ExplodedNode *Pred) { ProgramStateRef state = Pred->getState(); const StackFrameContext *calleeCtx = Pred->getLocationContext()->getCurrentStackFrame(); const LocationContext *callerCtx = calleeCtx->getParent(); const Stmt *CE = calleeCtx->getCallSite(); // If the callee returns an expression, bind its value to CallExpr. if (const ReturnStmt *RS = getReturnStmt(Pred)) { const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(RS, LCtx); state = state->BindExpr(CE, callerCtx, V); } // Bind the constructed object value to CXXConstructExpr. if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); SVal ThisV = state->getSVal(ThisR); // Always bind the region to the CXXConstructExpr. state = state->BindExpr(CCE, Pred->getLocationContext(), ThisV); } static SimpleProgramPointTag returnTag("ExprEngine : Call Return"); PostStmt Loc(CE, callerCtx, &returnTag); bool isNew; ExplodedNode *N = G.getNode(Loc, state, false, &isNew); N->addPredecessor(Pred, G); if (!isNew) return; // Perform the post-condition check of the CallExpr. ExplodedNodeSet Dst; NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), N); SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext, &Ctx); SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex()); getCheckerManager().runCheckersForPostStmt(Dst, N, CE, *this, /* wasInlined */ true); // Enqueue the next element in the block. for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { Engine.getWorkList()->enqueue(*I, calleeCtx->getCallSiteBlock(), calleeCtx->getIndex()+1); } }
void ExprEngine::VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, const Stmt *S, bool IsBaseDtor, ExplodedNode *Pred, ExplodedNodeSet &Dst, const EvalCallOptions &CallOpts) { assert(S && "A destructor without a trigger!"); const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl(); assert(RecordDecl && "Only CXXRecordDecls should have destructors"); const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor(); // FIXME: There should always be a Decl, otherwise the destructor call // shouldn't have been added to the CFG in the first place. if (!DtorDecl) { // Skip the invalid destructor. We cannot simply return because // it would interrupt the analysis instead. static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor"); // FIXME: PostImplicitCall with a null decl may crash elsewhere anyway. PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx, &T); NodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(PP, Pred->getState(), Pred); return; } CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXDestructorCall> Call = CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Call->getSourceRange().getBegin(), "Error evaluating destructor"); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this); ExplodedNodeSet DstInvalidated; StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call, CallOpts); getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, *Call, *this); }
void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set) { for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) { ExplodedNode *N = *I; // If we are in an inlined call, generate CallExitBegin node. if (N->getLocationContext()->getParent()) { N = generateCallExitBeginNode(N); if (N) WList->enqueue(N); } else { // TODO: We should run remove dead bindings here. G->addEndOfPath(N); NumPathsExplored++; } } }
void GRExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (CNE->isArray()) { // FIXME: allocating an array has not been handled. return; } unsigned Count = Builder->getCurrentBlockCount(); DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE, CNE->getType(), Count); const MemRegion *NewReg = cast<loc::MemRegionVal>(SymVal).getRegion(); QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); const ElementRegion *EleReg = getStoreManager().GetElementZeroRegion(NewReg, ObjTy); // Evaluate constructor arguments. const FunctionProtoType *FnType = NULL; const CXXConstructorDecl *CD = CNE->getConstructor(); if (CD) FnType = CD->getType()->getAs<FunctionProtoType>(); ExplodedNodeSet ArgsEvaluated; EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), FnType, Pred, ArgsEvaluated); // Initialize the object region and bind the 'new' expression. for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), E = ArgsEvaluated.end(); I != E; ++I) { const GRState *state = GetState(*I); if (ObjTy->isRecordType()) { state = state->InvalidateRegion(EleReg, CNE, Count); } else { if (CNE->hasInitializer()) { SVal V = state->getSVal(*CNE->constructor_arg_begin()); state = state->bindLoc(loc::MemRegionVal(EleReg), V); } else { // Explicitly set to undefined, because currently we retrieve symbolic // value from symbolic region. state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); } } state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); MakeNode(Dst, CNE, *I, state); } }
void ExprEngine::VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, const Stmt *S, bool IsBaseDtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); // FIXME: We need to run the same destructor on every element of the array. // This workaround will just run the first destructor (which will still // invalidate the entire array). // This is a loop because of multidimensional arrays. while (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) { ObjectType = AT->getElementType(); Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(), loc::MemRegionVal(Dest)).getAsRegion(); } const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl(); assert(RecordDecl && "Only CXXRecordDecls should have destructors"); const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXDestructorCall> Call = CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Call->getSourceRange().getBegin(), "Error evaluating destructor"); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this); ExplodedNodeSet DstInvalidated; StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call); ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, *Call, *this); }
// FIXME: This is the sort of code that should eventually live in a Core // checker rather than as a special case in ExprEngine. void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &Call) { SVal ThisVal; bool AlwaysReturnsLValue; if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { assert(Ctor->getDecl()->isTrivial()); assert(Ctor->getDecl()->isCopyOrMoveConstructor()); ThisVal = Ctor->getCXXThisVal(); AlwaysReturnsLValue = false; } else { assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial()); assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() == OO_Equal); ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal(); AlwaysReturnsLValue = true; } const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; Bldr.takeNodes(Pred); SVal V = Call.getArgSVal(0); // If the value being copied is not unknown, load from its location to get // an aggregate rvalue. if (Optional<Loc> L = V.getAs<Loc>()) V = Pred->getState()->getSVal(*L); else assert(V.isUnknown()); const Expr *CallExpr = Call.getOriginExpr(); evalBind(Dst, CallExpr, Pred, ThisVal, V, true); PostStmt PS(CallExpr, LCtx); for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); if (AlwaysReturnsLValue) State = State->BindExpr(CallExpr, LCtx, ThisVal); else State = bindReturnValue(Call, LCtx, State); Bldr.generateNode(PS, State, *I); } }
/// \brief Run checkers for evaluating a call. /// Only one checker will evaluate the call. void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng) { const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); for (ExplodedNodeSet::iterator NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { ExplodedNode *Pred = *NI; bool anyEvaluated = false; ExplodedNodeSet checkDst; NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); // Check if any of the EvalCall callbacks can evaluate the call. for (std::vector<EvalCallFunc>::iterator EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); EI != EE; ++EI) { ProgramPoint::Kind K = ProgramPoint::PostStmtKind; const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), EI->Checker); bool evaluated = false; { // CheckerContext generates transitions(populates checkDest) on // destruction, so introduce the scope to make sure it gets properly // populated. CheckerContext C(B, Eng, Pred, L); evaluated = (*EI)(CE, C); } assert(!(evaluated && anyEvaluated) && "There are more than one checkers evaluating the call"); if (evaluated) { anyEvaluated = true; Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. #endif } } // If none of the checkers evaluated the call, ask ExprEngine to handle it. if (!anyEvaluated) { NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); Eng.defaultEvalCall(B, Pred, Call); } } }
void GRExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { const GRState *state = GetState(*I); // Bind the temporary object to the value of the expression. Then bind // the expression to the location of the object. SVal V = state->getSVal(Ex); const MemRegion *R = ValMgr.getRegionManager().getCXXObjectRegion(Ex, Pred->getLocationContext()); state = state->bindLoc(loc::MemRegionVal(R), V); MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); } }
void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { const CFGBlock *Blk = L.getDst(); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { assert (L.getLocationContext()->getCFG()->getExit().size() == 0 && "EXIT block cannot contain Stmts."); // Process the final state transition. EndOfFunctionNodeBuilder Builder(Blk, Pred, this); SubEng.processEndOfFunction(Builder); // This path is done. Don't enqueue any more nodes. return; } // Call into the subengine to process entering the CFGBlock. ExplodedNodeSet dstNodes; BlockEntrance BE(Blk, Pred->getLocationContext()); GenericNodeBuilder<BlockEntrance> nodeBuilder(*this, Pred, BE); SubEng.processCFGBlockEntrance(dstNodes, nodeBuilder); if (dstNodes.empty()) { if (!nodeBuilder.hasGeneratedNode) { // Auto-generate a node and enqueue it to the worklist. generateNode(BE, Pred->State, Pred); } } else { for (ExplodedNodeSet::iterator I = dstNodes.begin(), E = dstNodes.end(); I != E; ++I) { WList->enqueue(*I); } } for (SmallVectorImpl<ExplodedNode*>::const_iterator I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end(); I != E; ++I) { blocksExhausted.push_back(std::make_pair(L, *I)); } }
void ExprEngine:: VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: Prechecks eventually go in ::Visit(). ExplodedNodeSet CheckedSet; getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this); ExplodedNodeSet EvalSet; StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); QualType T = Ex->getTypeOfArgument(); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { if (Ex->getKind() == UETT_SizeOf) { if (!T->isIncompleteType() && !T->isConstantSizeType()) { assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); // FIXME: Add support for VLA type arguments and VLA expressions. // When that happens, we should probably refactor VLASizeChecker's code. continue; } else if (T->getAs<ObjCObjectType>()) { // Some code tries to take the sizeof an ObjCObjectType, relying that // the compiler has laid out its representation. Just report Unknown // for these. continue; } } APSInt Value = Ex->EvaluateKnownConstInt(getContext()); CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); ProgramStateRef state = (*I)->getState(); state = state->BindExpr(Ex, (*I)->getLocationContext(), svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType())); Bldr.generateNode(Ex, *I, state); } getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); }
/// \brief Run checkers for evaluating a call. /// Only one checker will evaluate the call. void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallExpr *CE, ExprEngine &Eng, GraphExpander *defaultEval) { if (EvalCallCheckers.empty() && defaultEval == 0) { Dst.insert(Src); return; } for (ExplodedNodeSet::iterator NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { ExplodedNode *Pred = *NI; bool anyEvaluated = false; for (std::vector<EvalCallFunc>::iterator EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); EI != EE; ++EI) { ExplodedNodeSet checkDst; CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, EI->Checker, ProgramPoint::PostStmtKind, 0, CE); bool evaluated = (*EI)(CE, C); assert(!(evaluated && anyEvaluated) && "There are more than one checkers evaluating the call"); if (evaluated) { anyEvaluated = true; Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. #endif } } if (!anyEvaluated) { if (defaultEval) defaultEval->expandGraph(Dst, Pred); else Dst.insert(Pred); } } }
void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (E->isElidable()) { VisitAggExpr(E->getArg(0), Dest, Pred, Dst); return; } const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) // FIXME: invalidate the object. return; // Evaluate other arguments. ExplodedNodeSet ArgsEvaluated; const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); EvalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, ArgsEvaluated); // The callee stack frame context used to create the 'this' parameter region. const StackFrameContext *SFC = AMgr.getStackFrame(CD, Pred->getLocationContext(), E, Builder->getBlock(), Builder->getIndex()); const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); CallEnter Loc(E, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), NE = ArgsEvaluated.end(); NI != NE; ++NI) { const GRState *state = GetState(*NI); // Setup 'this' region. state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); ExplodedNode *N = Builder->generateNode(Loc, state, Pred); if (N) Dst.Add(N); } }
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, const MemRegion *Dest, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { CXXConstructorCall Call(CE, Dest, Pred->getState(), Pred->getLocationContext()); ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit, Call, *this); ExplodedNodeSet DstInvalidated; for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(DstInvalidated, *I, Call); ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated, Call, *this); getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); }
void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ProgramStateRef State = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), CNE->getStartLoc(), "Error evaluating New Allocator Call"); CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXAllocatorCall> Call = CEMgr.getCXXAllocatorCall(CNE, State, LCtx); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this); ExplodedNodeSet DstInvalidated; StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call); getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, *Call, *this); }