diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 284 |
1 files changed, 195 insertions, 89 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 437af86ccf..bfe4e15a71 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -106,7 +106,8 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); - if (!T->isIntegerType()) + const BuiltinType *BT = dyn_cast<BuiltinType>(T); + if (!BT || !BT->isInteger()) break; const MemRegion *R = state->getRegion(PD, InitLoc); @@ -171,18 +172,29 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, const Expr *Ex, const Expr *Result) { SVal V = State->getSVal(Ex, LC); - if (!Result && !V.getAs<NonLoc>()) - return State; + if (!Result) { + // If we don't have an explicit result expression, we're in "if needed" + // mode. Only create a region if the current value is a NonLoc. + if (!V.getAs<NonLoc>()) + return State; + Result = Ex; + } else { + // We need to create a region no matter what. For sanity, make sure we don't + // try to stuff a Loc into a non-pointer temporary region. + assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()) || + Result->getType()->isMemberPointerType()); + } ProgramStateManager &StateMgr = State->getStateManager(); MemRegionManager &MRMgr = StateMgr.getRegionManager(); StoreManager &StoreMgr = StateMgr.getStoreManager(); // We need to be careful about treating a derived type's value as - // bindings for a base type. Start by stripping and recording base casts. + // bindings for a base type. Unless we're creating a temporary pointer region, + // start by stripping and recording base casts. SmallVector<const CastExpr *, 4> Casts; const Expr *Inner = Ex->IgnoreParens(); - if (V.getAs<NonLoc>()) { + if (!Loc::isLocType(Result->getType())) { while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) { if (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_UncheckedDerivedToBase) @@ -195,8 +207,13 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, } // Create a temporary object region for the inner expression (which may have - // a more derived type) and bind the NonLoc value into it. - SVal Reg = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(Inner, LC)); + // a more derived type) and bind the value into it. + const TypedValueRegion *TR = MRMgr.getCXXTempObjectRegion(Inner, LC); + SVal Reg = loc::MemRegionVal(TR); + + if (V.isUnknown()) + V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(), + currBldrCtx->blockCount()); State = State->bindLoc(Reg, V); // Re-apply the casts (from innermost to outermost) for type sanity. @@ -206,7 +223,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, Reg = StoreMgr.evalDerivedToBase(Reg, *I); } - State = State->BindExpr(Result ? Result : Ex, LC, Reg); + State = State->BindExpr(Result, LC, Reg); return State; } @@ -423,8 +440,8 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, ProgramStateRef State = Pred->getState(); SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame)); - PostInitializer PP(BMI, stackFrame); ExplodedNodeSet Tmp(Pred); + SVal FieldLoc; // Evaluate the initializer, if necessary if (BMI->isAnyMemberInitializer()) { @@ -432,15 +449,43 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, // but non-objects must be copied in from the initializer. const Expr *Init = BMI->getInit()->IgnoreImplicit(); if (!isa<CXXConstructExpr>(Init)) { - SVal FieldLoc; - if (BMI->isIndirectMemberInitializer()) + const ValueDecl *Field; + if (BMI->isIndirectMemberInitializer()) { + Field = BMI->getIndirectMember(); FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); - else + } else { + Field = BMI->getMember(); FieldLoc = State->getLValue(BMI->getMember(), thisVal); + } - SVal InitVal = State->getSVal(BMI->getInit(), stackFrame); + SVal InitVal; + if (BMI->getNumArrayIndices() > 0) { + // Handle arrays of trivial type. We can represent this with a + // primitive load/copy from the base array region. + const ArraySubscriptExpr *ASE; + while ((ASE = dyn_cast<ArraySubscriptExpr>(Init))) + Init = ASE->getBase()->IgnoreImplicit(); + + SVal LValue = State->getSVal(Init, stackFrame); + if (Optional<Loc> LValueLoc = LValue.getAs<Loc>()) + InitVal = State->getSVal(*LValueLoc); + + // If we fail to get the value for some reason, use a symbolic value. + if (InitVal.isUnknownOrUndef()) { + SValBuilder &SVB = getSValBuilder(); + InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame, + Field->getType(), + currBldrCtx->blockCount()); + } + } else { + InitVal = State->getSVal(BMI->getInit(), stackFrame); + } + assert(Tmp.size() == 1 && "have not generated any new nodes yet"); + assert(*Tmp.begin() == Pred && "have not generated any new nodes yet"); Tmp.clear(); + + PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); } } else { @@ -450,6 +495,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, // Construct PostInitializer nodes whether the state changed or not, // so that the diagnostics don't get confused. + PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); ExplodedNodeSet Dst; NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { @@ -488,18 +534,20 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - ProgramStateRef state = Pred->getState(); const VarDecl *varDecl = Dtor.getVarDecl(); - QualType varType = varDecl->getType(); - if (const ReferenceType *refType = varType->getAs<ReferenceType>()) - varType = refType->getPointeeType(); + ProgramStateRef state = Pred->getState(); + SVal dest = state->getLValue(varDecl, Pred->getLocationContext()); + const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion(); - Loc dest = state->getLValue(varDecl, Pred->getLocationContext()); + if (const ReferenceType *refType = varType->getAs<ReferenceType>()) { + varType = refType->getPointeeType(); + Region = state->getSVal(Region).getAsRegion(); + } - VisitCXXDestructor(varType, dest.castAs<loc::MemRegionVal>().getRegion(), - Dtor.getTriggerStmt(), /*IsBase=*/ false, Pred, Dst); + VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false, + Pred, Dst); } void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, @@ -556,11 +604,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, switch (S->getStmtClass()) { // C++ and ARC stuff we don't support yet. case Expr::ObjCIndirectCopyRestoreExprClass: + case Stmt::CXXDefaultInitExprClass: case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: + case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::UnaryTypeTraitExprClass: @@ -607,6 +657,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: case Expr::MSDependentExistsStmtClass: + case Stmt::CapturedStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -690,21 +741,22 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S); const Expr *ArgE = DefaultE->getExpr(); - // Avoid creating and destroying a lot of APSInts. - SVal V; - llvm::APSInt Result; + bool IsTemporary = false; + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(ArgE)) { + ArgE = MTE->GetTemporaryExpr(); + IsTemporary = true; + } + + Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE); + if (!ConstantVal) + ConstantVal = UnknownVal(); for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); - - if (ArgE->EvaluateAsInt(Result, getContext())) - V = svalBuilder.makeIntVal(Result); - else - V = State->getSVal(ArgE, LCtx); - - State = State->BindExpr(DefaultE, LCtx, V); - if (DefaultE->isGLValue()) + State = State->BindExpr(DefaultE, LCtx, *ConstantVal); + if (IsTemporary) State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE, DefaultE); Bldr2.generateNode(S, *I, State); @@ -814,9 +866,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef NewState = createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); - if (NewState != State) + if (NewState != State) { Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, ProgramPoint::PreStmtKind); + // Did we cache out? + if (!Pred) + break; + } } } // FALLTHROUGH @@ -1189,7 +1245,7 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, while (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) { QualType T = CE->getType(); - if (!T->isIntegerType()) + if (!T->isIntegralOrEnumerationType()) return UnknownVal(); uint64_t newBits = Ctx.getTypeSize(T); @@ -1204,7 +1260,8 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, // We reached a non-cast. Is it a symbolic value? QualType T = Ex->getType(); - if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits) + if (!bitsInit || !T->isIntegralOrEnumerationType() || + Ctx.getTypeSize(T) > bits) return UnknownVal(); return state->getSVal(Ex, LCtx); @@ -1296,7 +1353,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, if (X.isUnknownOrUndef()) { // Give it a chance to recover from unknown. if (const Expr *Ex = dyn_cast<Expr>(Condition)) { - if (Ex->getType()->isIntegerType()) { + if (Ex->getType()->isIntegralOrEnumerationType()) { // Try to recover some path-sensitivity. Right now casts of symbolic // integers that promote their values are currently not tracked well. // If 'Condition' is such an expression, try and recover the @@ -1344,6 +1401,34 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, currBldrCtx = 0; } +/// The GDM component containing the set of global variables which have been +/// previously initialized with explicit initializers. +REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet, + llvm::ImmutableSet<const VarDecl *>) + +void ExprEngine::processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext &BuilderCtx, + ExplodedNode *Pred, + clang::ento::ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) { + currBldrCtx = &BuilderCtx; + + const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); + ProgramStateRef state = Pred->getState(); + bool initHasRun = state->contains<InitializedGlobalsSet>(VD); + BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF); + + if (!initHasRun) { + state = state->add<InitializedGlobalsSet>(VD); + } + + builder.generateNode(state, initHasRun, Pred); + builder.markInfeasible(!initHasRun); + + currBldrCtx = 0; +} + /// processIndirectGoto - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { @@ -1692,12 +1777,6 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, if (StoredVal != Val) escapes = (State == (State->bindLoc(*regionLoc, Val))); } - if (!escapes) { - // Case 4: We do not currently model what happens when a symbol is - // assigned to a struct field, so be conservative here and let the symbol - // go. TODO: This could definitely be improved upon. - escapes = !isa<VarRegion>(regionLoc->getRegion()); - } } // If our store can represent the binding and we aren't storing to something @@ -1720,11 +1799,12 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, } ProgramStateRef -ExprEngine::processPointerEscapedOnInvalidateRegions(ProgramStateRef State, +ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, const InvalidatedSymbols *Invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) { + const CallEvent *Call, + bool IsConst) { if (!Invalidated || Invalidated->empty()) return State; @@ -1733,8 +1813,19 @@ ExprEngine::processPointerEscapedOnInvalidateRegions(ProgramStateRef State, return getCheckerManager().runCheckersForPointerEscape(State, *Invalidated, 0, - PSK_EscapeOther); - + PSK_EscapeOther, + IsConst); + + // Note: Due to current limitations of RegionStore, we only process the top + // level const pointers correctly. The lower level const pointers are + // currently treated as non-const. + if (IsConst) + return getCheckerManager().runCheckersForPointerEscape(State, + *Invalidated, + Call, + PSK_DirectEscapeOnCall, + true); + // If the symbols were invalidated by a call, we want to find out which ones // were invalidated directly due to being arguments to the call. InvalidatedSymbols SymbolsDirectlyInvalidated; @@ -2161,54 +2252,27 @@ struct DOTGraphTraits<ExplodedNode*> : break; } - default: { - if (Optional<StmtPoint> L = Loc.getAs<StmtPoint>()) { - const Stmt *S = L->getStmt(); - - Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; + case ProgramPoint::PostInitializerKind: { + Out << "PostInitializer: "; + const CXXCtorInitializer *Init = + Loc.castAs<PostInitializer>().getInitializer(); + if (const FieldDecl *FD = Init->getAnyMember()) + Out << *FD; + else { + QualType Ty = Init->getTypeSourceInfo()->getType(); + Ty = Ty.getLocalUnqualifiedType(); LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); - printLocation(Out, S->getLocStart()); - - if (Loc.getAs<PreStmt>()) - Out << "\\lPreStmt\\l;"; - else if (Loc.getAs<PostLoad>()) - Out << "\\lPostLoad\\l;"; - else if (Loc.getAs<PostStore>()) - Out << "\\lPostStore\\l"; - else if (Loc.getAs<PostLValue>()) - Out << "\\lPostLValue\\l"; - -#if 0 - // FIXME: Replace with a general scheme to determine - // the name of the check. - if (GraphPrintCheckerState->isImplicitNullDeref(N)) - Out << "\\|Implicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isExplicitNullDeref(N)) - Out << "\\|Explicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isUndefDeref(N)) - Out << "\\|Dereference of undefialied value.\\l"; - else if (GraphPrintCheckerState->isUndefStore(N)) - Out << "\\|Store to Undefined Loc."; - else if (GraphPrintCheckerState->isUndefResult(N)) - Out << "\\|Result of operation is undefined."; - else if (GraphPrintCheckerState->isNoReturnCall(N)) - Out << "\\|Call to function marked \"noreturn\"."; - else if (GraphPrintCheckerState->isBadCall(N)) - Out << "\\|Call to NULL/Undefined."; - else if (GraphPrintCheckerState->isUndefArg(N)) - Out << "\\|Argument in call is undefined"; -#endif - - break; + Ty.print(Out, LO); } + break; + } + case ProgramPoint::BlockEdgeKind: { const BlockEdge &E = Loc.castAs<BlockEdge>(); Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" << E.getDst()->getBlockID() << ')'; if (const Stmt *T = E.getSrc()->getTerminator()) { - SourceLocation SLoc = T->getLocStart(); Out << "\\|Terminator: "; @@ -2267,6 +2331,48 @@ struct DOTGraphTraits<ExplodedNode*> : Out << "\\|Control-flow based on\\lUndefined value.\\l"; } #endif + break; + } + + default: { + const Stmt *S = Loc.castAs<StmtPoint>().getStmt(); + + Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; + LangOptions LO; // FIXME. + S->printPretty(Out, 0, PrintingPolicy(LO)); + printLocation(Out, S->getLocStart()); + + if (Loc.getAs<PreStmt>()) + Out << "\\lPreStmt\\l;"; + else if (Loc.getAs<PostLoad>()) + Out << "\\lPostLoad\\l;"; + else if (Loc.getAs<PostStore>()) + Out << "\\lPostStore\\l"; + else if (Loc.getAs<PostLValue>()) + Out << "\\lPostLValue\\l"; + +#if 0 + // FIXME: Replace with a general scheme to determine + // the name of the check. + if (GraphPrintCheckerState->isImplicitNullDeref(N)) + Out << "\\|Implicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isExplicitNullDeref(N)) + Out << "\\|Explicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isUndefDeref(N)) + Out << "\\|Dereference of undefialied value.\\l"; + else if (GraphPrintCheckerState->isUndefStore(N)) + Out << "\\|Store to Undefined Loc."; + else if (GraphPrintCheckerState->isUndefResult(N)) + Out << "\\|Result of operation is undefined."; + else if (GraphPrintCheckerState->isNoReturnCall(N)) + Out << "\\|Call to function marked \"noreturn\"."; + else if (GraphPrintCheckerState->isBadCall(N)) + Out << "\\|Call to NULL/Undefined."; + else if (GraphPrintCheckerState->isUndefArg(N)) + Out << "\\|Argument in call is undefined"; +#endif + + break; } } @@ -2301,7 +2407,7 @@ GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator> void ExprEngine::ViewGraph(bool trim) { #ifndef NDEBUG if (trim) { - std::vector<ExplodedNode*> Src; + std::vector<const ExplodedNode*> Src; // Flush any outstanding reports to make sure we cover all the nodes. // This does not cause them to get displayed. @@ -2315,7 +2421,7 @@ void ExprEngine::ViewGraph(bool trim) { if (N) Src.push_back(N); } - ViewGraph(&Src[0], &Src[0]+Src.size()); + ViewGraph(Src); } else { GraphPrintCheckerState = this; @@ -2329,12 +2435,12 @@ void ExprEngine::ViewGraph(bool trim) { #endif } -void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) { +void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { #ifndef NDEBUG GraphPrintCheckerState = this; GraphPrintSourceManager = &getContext().getSourceManager(); - std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first); + OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes)); if (!TrimmedG.get()) llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; |