diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 311 |
1 files changed, 193 insertions, 118 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 9907d0cbf9b8..4e4095c5e0d8 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -13,8 +13,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ExprEngine" - #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CharUnits.h" @@ -40,6 +38,8 @@ using namespace clang; using namespace ento; using llvm::APSInt; +#define DEBUG_TYPE "ExprEngine" + STATISTIC(NumRemoveDeadBindings, "The # of times RemoveDeadBindings is called"); STATISTIC(NumMaxBlockCountReached, @@ -55,6 +55,8 @@ STATISTIC(NumTimesRetriedWithoutInlining, // Engine construction and deletion. //===----------------------------------------------------------------------===// +static const char* TagProviderName = "ExprEngine"; + ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS, @@ -68,7 +70,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, this), SymMgr(StateMgr.getSymbolManager()), svalBuilder(StateMgr.getSValBuilder()), - currStmtIdx(0), currBldrCtx(0), + currStmtIdx(0), currBldrCtx(nullptr), ObjCNoRet(mgr.getASTContext()), ObjCGCEnabled(gcEnabled), BR(mgr, *this), VisitedCallees(VisitedCalleesIn), @@ -118,7 +120,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { SVal V = state->getSVal(loc::MemRegionVal(R)); SVal Constraint_untested = evalBinOp(state, BO_GT, V, svalBuilder.makeZeroVal(T), - getContext().IntTy); + svalBuilder.getConditionType()); Optional<DefinedOrUnknownSVal> Constraint = Constraint_untested.getAs<DefinedOrUnknownSVal>(); @@ -153,7 +155,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { // top-level function. This is our starting assumption for // analyzing an "open" program. const StackFrameContext *SFC = InitLoc->getCurrentStackFrame(); - if (SFC->getParent() == 0) { + if (SFC->getParent() == nullptr) { loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC); SVal V = state->getSVal(L); if (Optional<Loc> LV = V.getAs<Loc>()) { @@ -209,7 +211,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, // Create a temporary object region for the inner expression (which may have // a more derived type) and bind the value into it. - const TypedValueRegion *TR = NULL; + const TypedValueRegion *TR = nullptr; if (const MaterializeTemporaryExpr *MT = dyn_cast<MaterializeTemporaryExpr>(Result)) { StorageDuration SD = MT->getStorageDuration(); @@ -286,6 +288,10 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, case CFGElement::Initializer: ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred); return; + case CFGElement::NewAllocator: + ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(), + Pred); + return; case CFGElement::AutomaticObjectDtor: case CFGElement::DeleteDtor: case CFGElement::BaseDtor: @@ -329,7 +335,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, const Stmt *DiagnosticStmt, ProgramPoint::Kind K) { assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind || - ReferenceStmt == 0 || isa<ReturnStmt>(ReferenceStmt)) + ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt)) && "PostStmt is not generally supported by the SymbolReaper yet"); assert(LC && "Must pass the current (or expiring) LocationContext"); @@ -350,7 +356,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, LC = LC->getParent(); } - const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : 0; + const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : nullptr; SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager()); getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); @@ -362,7 +368,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // Process any special transfer function for dead symbols. // A tag to track convenience transitions, which can be removed at cleanup. - static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node"); + static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node"); if (!SymReaper.hasDeadSymbols()) { // Generate a CleanedNode that has the environment and store cleaned // up. Since no symbols are dead, we can optimize and not clean out @@ -547,6 +553,25 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); } +void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE, + ExplodedNode *Pred) { + ExplodedNodeSet Dst; + AnalysisManager &AMgr = getAnalysisManager(); + AnalyzerOptions &Opts = AMgr.options; + // TODO: We're not evaluating allocators for all cases just yet as + // we're not handling the return value correctly, which causes false + // positives when the alpha.cplusplus.NewDeleteLeaks check is on. + if (Opts.mayInlineCXXAllocator()) + VisitCXXNewAllocatorCall(NE, Pred, Dst); + else { + NodeBuilder Bldr(Pred, Dst, *currBldrCtx); + const LocationContext *LCtx = Pred->getLocationContext(); + PostImplicitCall PP(NE->getOperatorNew(), NE->getLocStart(), LCtx); + Bldr.generateNode(PP, Pred->getState(), Pred); + } + Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); +} + void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -598,7 +623,6 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const LocationContext *LCtx = Pred->getLocationContext(); - ProgramStateRef State = Pred->getState(); const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor, @@ -640,7 +664,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, // FIXME: Inlining of temporary destructors is not supported yet anyway, so we // just put a NULL region for now. This will need to be changed later. - VisitCXXDestructor(varType, NULL, D.getBindTemporaryExpr(), + VisitCXXDestructor(varType, nullptr, D.getBindTemporaryExpr(), /*IsBase=*/ false, Pred, Dst); } @@ -664,8 +688,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: - case Stmt::UnaryTypeTraitExprClass: - case Stmt::BinaryTypeTraitExprClass: case Stmt::TypeTraitExprClass: case Stmt::ArrayTypeTraitExprClass: case Stmt::ExpressionTraitExprClass: @@ -677,6 +699,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::FunctionParmPackExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: + case Stmt::SEHLeaveStmtClass: case Stmt::LambdaExprClass: case Stmt::SEHFinallyStmtClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); @@ -709,6 +732,20 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Expr::MSDependentExistsStmtClass: case Stmt::CapturedStmtClass: case Stmt::OMPParallelDirectiveClass: + case Stmt::OMPSimdDirectiveClass: + case Stmt::OMPForDirectiveClass: + case Stmt::OMPSectionsDirectiveClass: + case Stmt::OMPSectionDirectiveClass: + case Stmt::OMPSingleDirectiveClass: + case Stmt::OMPMasterDirectiveClass: + case Stmt::OMPCriticalDirectiveClass: + case Stmt::OMPParallelForDirectiveClass: + case Stmt::OMPParallelSectionsDirectiveClass: + case Stmt::OMPTaskDirectiveClass: + case Stmt::OMPTaskyieldDirectiveClass: + case Stmt::OMPBarrierDirectiveClass: + case Stmt::OMPTaskwaitDirectiveClass: + case Stmt::OMPFlushDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -848,7 +885,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, it != et; ++it) { ExplodedNode *N = *it; const LocationContext *LCtx = N->getLocationContext(); - SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType, + SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + resultType, currBldrCtx->blockCount()); ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); Bldr2.generateNode(S, N, state); @@ -928,7 +966,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ProgramStateRef NewState = createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); if (NewState != State) { - Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, + Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/nullptr, ProgramPoint::PreStmtKind); // Did we cache out? if (!Pred) @@ -1187,14 +1225,14 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N, const StackFrameContext *CalleeSF = CalleeLC->getCurrentStackFrame(); const StackFrameContext *CallerSF = CalleeSF->getParent()->getCurrentStackFrame(); assert(CalleeSF && CallerSF); - ExplodedNode *BeforeProcessingCall = 0; + ExplodedNode *BeforeProcessingCall = nullptr; const Stmt *CE = CalleeSF->getCallSite(); // Find the first node before we started processing the call expression. while (N) { ProgramPoint L = N->getLocation(); BeforeProcessingCall = N; - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? nullptr : *(N->pred_begin()); // Skip the nodes corresponding to the inlined code. if (L.getLocationContext()->getCurrentStackFrame() != CallerSF) @@ -1253,7 +1291,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, // FIXME: Refactor this into a checker. if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) { - static SimpleProgramPointTag tag("ExprEngine : Block count exceeded"); + static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded"); const ExplodedNode *Sink = nodeBuilder.generateSink(Pred->getState(), Pred, &tag); @@ -1329,6 +1367,33 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, return state->getSVal(Ex, LCtx); } +#ifndef NDEBUG +static const Stmt *getRightmostLeaf(const Stmt *Condition) { + while (Condition) { + const BinaryOperator *BO = dyn_cast<BinaryOperator>(Condition); + if (!BO || !BO->isLogicalOp()) { + return Condition; + } + Condition = BO->getRHS()->IgnoreParens(); + } + return nullptr; +} +#endif + +// Returns the condition the branch at the end of 'B' depends on and whose value +// has been evaluated within 'B'. +// In most cases, the terminator condition of 'B' will be evaluated fully in +// the last statement of 'B'; in those cases, the resolved condition is the +// given 'Condition'. +// If the condition of the branch is a logical binary operator tree, the CFG is +// optimized: in that case, we know that the expression formed by all but the +// rightmost leaf of the logical binary operator tree must be true, and thus +// the branch condition is at this point equivalent to the truth value of that +// rightmost leaf; the CFG block thus only evaluates this rightmost leaf +// expression in its final statement. As the full condition in that case was +// not evaluated, and is thus not in the SVal cache, we need to use that leaf +// expression to evaluate the truth value of the condition in the current state +// space. static const Stmt *ResolveCondition(const Stmt *Condition, const CFGBlock *B) { if (const Expr *Ex = dyn_cast<Expr>(Condition)) @@ -1338,6 +1403,12 @@ static const Stmt *ResolveCondition(const Stmt *Condition, if (!BO || !BO->isLogicalOp()) return Condition; + // FIXME: This is a workaround until we handle temporary destructor branches + // correctly; currently, temporary destructor branches lead to blocks that + // only have a terminator (and no statements). These blocks violate the + // invariant this function assumes. + if (B->getTerminator().isTemporaryDtorsBranch()) return Condition; + // For logical operations, we still have the case where some branches // use the traditional "merge" approach and others sink the branch // directly into the basic blocks representing the logical operation. @@ -1352,18 +1423,9 @@ static const Stmt *ResolveCondition(const Stmt *Condition, Optional<CFGStmt> CS = Elem.getAs<CFGStmt>(); if (!CS) continue; - if (CS->getStmt() != Condition) - break; - return Condition; - } - - assert(I != E); - - while (Condition) { - BO = dyn_cast<BinaryOperator>(Condition); - if (!BO || !BO->isLogicalOp()) - return Condition; - Condition = BO->getRHS()->IgnoreParens(); + const Stmt *LastStmt = CS->getStmt(); + assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition)); + return LastStmt; } llvm_unreachable("could not resolve condition"); } @@ -1443,7 +1505,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, DefinedSVal V = X.castAs<DefinedSVal>(); ProgramStateRef StTrue, StFalse; - tie(StTrue, StFalse) = PrevState->assume(V); + std::tie(StTrue, StFalse) = PrevState->assume(V); // Process the true branch. if (builder.isFeasible(true)) { @@ -1461,7 +1523,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, builder.markInfeasible(false); } } - currBldrCtx = 0; + currBldrCtx = nullptr; } /// The GDM component containing the set of global variables which have been @@ -1490,7 +1552,7 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS, builder.generateNode(state, initHasRun, Pred); builder.markInfeasible(!initHasRun); - currBldrCtx = 0; + currBldrCtx = nullptr; } /// processIndirectGoto - Called by CoreEngine. Used to generate successor @@ -1631,7 +1693,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { } else { defaultIsFeasible = false; - DefaultSt = NULL; + DefaultSt = nullptr; } } @@ -1692,7 +1754,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1704,7 +1766,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1715,7 +1777,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy, currBldrCtx->blockCount()); state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1745,82 +1807,91 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, state->getSVal(Idx, LCtx), state->getSVal(Base, LCtx)); assert(A->isGLValue()); - Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0, + Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), nullptr, ProgramPoint::PostLValueKind); } } /// VisitMemberExpr - Transfer function for member expressions. void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, - ExplodedNodeSet &TopDst) { + ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx); - ExplodedNodeSet Dst; + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this); + + ExplodedNodeSet EvalSet; ValueDecl *Member = M->getMemberDecl(); // Handle static member variables and enum constants accessed via // member syntax. if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) { - Bldr.takeNodes(Pred); - VisitCommonDeclRefExpr(M, Member, Pred, Dst); - Bldr.addNodes(Dst); - return; - } - - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - Expr *BaseExpr = M->getBase(); + ExplodedNodeSet Dst; + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + VisitCommonDeclRefExpr(M, Member, Pred, EvalSet); + } + } else { + StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); + ExplodedNodeSet Tmp; - // Handle C++ method calls. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { - if (MD->isInstance()) - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + ProgramStateRef state = (*I)->getState(); + const LocationContext *LCtx = (*I)->getLocationContext(); + Expr *BaseExpr = M->getBase(); - SVal MDVal = svalBuilder.getFunctionPointer(MD); - state = state->BindExpr(M, LCtx, MDVal); + // Handle C++ method calls. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - Bldr.generateNode(M, Pred, state); - return; - } + SVal MDVal = svalBuilder.getFunctionPointer(MD); + state = state->BindExpr(M, LCtx, MDVal); - // Handle regular struct fields / member variables. - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - SVal baseExprVal = state->getSVal(BaseExpr, LCtx); - - FieldDecl *field = cast<FieldDecl>(Member); - SVal L = state->getLValue(field, baseExprVal); - - if (M->isGLValue() || M->getType()->isArrayType()) { - - // We special case rvalue of array type because the analyzer cannot reason - // about it, since we expect all regions to be wrapped in Locs. So we will - // treat these as lvalues assuming that they will decay to pointers as soon - // as they are used. - if (!M->isGLValue()) { - assert(M->getType()->isArrayType()); - const ImplicitCastExpr *PE = - dyn_cast<ImplicitCastExpr>(Pred->getParentMap().getParent(M)); - if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { - assert(false && - "We assume that array is always wrapped in ArrayToPointerDecay"); - L = UnknownVal(); + Bldr.generateNode(M, *I, state); + continue; } - } - if (field->getType()->isReferenceType()) { - if (const MemRegion *R = L.getAsRegion()) - L = state->getSVal(R); - else - L = UnknownVal(); - } + // Handle regular struct fields / member variables. + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal baseExprVal = state->getSVal(BaseExpr, LCtx); + + FieldDecl *field = cast<FieldDecl>(Member); + SVal L = state->getLValue(field, baseExprVal); + + if (M->isGLValue() || M->getType()->isArrayType()) { + // We special-case rvalues of array type because the analyzer cannot + // reason about them, since we expect all regions to be wrapped in Locs. + // We instead treat these as lvalues and assume that they will decay to + // pointers as soon as they are used. + if (!M->isGLValue()) { + assert(M->getType()->isArrayType()); + const ImplicitCastExpr *PE = + dyn_cast<ImplicitCastExpr>((*I)->getParentMap().getParent(M)); + if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { + llvm_unreachable("should always be wrapped in ArrayToPointerDecay"); + } + } - Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0, - ProgramPoint::PostLValueKind); - } else { - Bldr.takeNodes(Pred); - evalLoad(Dst, M, M, Pred, state, L); - Bldr.addNodes(Dst); + if (field->getType()->isReferenceType()) { + if (const MemRegion *R = L.getAsRegion()) + L = state->getSVal(R); + else + L = UnknownVal(); + } + + Bldr.generateNode(M, *I, state->BindExpr(M, LCtx, L), nullptr, + ProgramPoint::PostLValueKind); + } else { + Bldr.takeNodes(*I); + evalLoad(Tmp, M, M, *I, state, L); + Bldr.addNodes(Tmp); + } + } } + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this); } namespace { @@ -1830,7 +1901,7 @@ public: CollectReachableSymbolsCallback(ProgramStateRef State) {} const InvalidatedSymbols &getSymbols() const { return Symbols; } - bool VisitSymbol(SymbolRef Sym) { + bool VisitSymbol(SymbolRef Sym) override { Symbols.insert(Sym); return true; } @@ -1876,9 +1947,9 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols(); State = getCheckerManager().runCheckersForPointerEscape(State, EscapedSymbols, - /*CallEvent*/ 0, + /*CallEvent*/ nullptr, PSK_EscapeOnBind, - 0); + nullptr); return State; } @@ -1897,7 +1968,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, if (!Call) return getCheckerManager().runCheckersForPointerEscape(State, *Invalidated, - 0, + nullptr, PSK_EscapeOther, &ITraits); @@ -1954,7 +2025,8 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, // If the location is not a 'Loc', it will already be handled by // the checkers. There is nothing left to do. if (!location.getAs<Loc>()) { - const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/0, /*tag*/0); + const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/nullptr, + /*tag*/nullptr); ProgramStateRef state = Pred->getState(); state = processPointerEscapedOnBind(state, location, Val); Bldr.generateNode(L, state, Pred); @@ -1975,13 +2047,13 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, state = state->bindLoc(location.castAs<Loc>(), Val, /* notifyChanges = */ !atDeclInit); - const MemRegion *LocReg = 0; + const MemRegion *LocReg = nullptr; if (Optional<loc::MemRegionVal> LocRegVal = location.getAs<loc::MemRegionVal>()) { LocReg = LocRegVal->getRegion(); } - - const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0); + + const ProgramPoint L = PostStore(StoreE, LC, LocReg, nullptr); Bldr.generateNode(L, state, PredI); } } @@ -2037,7 +2109,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, QualType ValTy = TR->getValueType(); if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) { static SimpleProgramPointTag - loadReferenceTag("ExprEngine : Load Reference"); + loadReferenceTag(TagProviderName, "Load Reference"); ExplodedNodeSet Tmp; evalLoadCommon(Tmp, NodeEx, BoundEx, Pred, state, location, &loadReferenceTag, @@ -2120,7 +2192,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, // instead "int *p" is noted as // "Variable 'p' initialized to a null pointer value" - static SimpleProgramPointTag tag("ExprEngine: Location"); + static SimpleProgramPointTag tag(TagProviderName, "Location"); Bldr.generateNode(NodeEx, Pred, state, &tag); } ExplodedNodeSet Tmp; @@ -2132,8 +2204,10 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, std::pair<const ProgramPointTag *, const ProgramPointTag*> ExprEngine::geteagerlyAssumeBinOpBifurcationTags() { static SimpleProgramPointTag - eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"), - eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False"); + eagerlyAssumeBinOpBifurcationTrue(TagProviderName, + "Eagerly Assume True"), + eagerlyAssumeBinOpBifurcationFalse(TagProviderName, + "Eagerly Assume False"); return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue, &eagerlyAssumeBinOpBifurcationFalse); } @@ -2161,7 +2235,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, geteagerlyAssumeBinOpBifurcationTags(); ProgramStateRef StateTrue, StateFalse; - tie(StateTrue, StateFalse) = state->assume(*SEV); + std::tie(StateTrue, StateFalse) = state->assume(*SEV); // First assume that the condition is true. if (StateTrue) { @@ -2192,9 +2266,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, ProgramStateRef state = Pred->getState(); - for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(), - OE = A->end_outputs(); OI != OE; ++OI) { - SVal X = state->getSVal(*OI, Pred->getLocationContext()); + for (const Expr *O : A->outputs()) { + SVal X = state->getSVal(O, Pred->getLocationContext()); assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef. if (Optional<Loc> LV = X.getAs<Loc>()) @@ -2368,11 +2441,12 @@ struct DOTGraphTraits<ExplodedNode*> : if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) { Out << "\\lcase "; LangOptions LO; // FIXME. - C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); + if (C->getLHS()) + C->getLHS()->printPretty(Out, nullptr, PrintingPolicy(LO)); if (const Stmt *RHS = C->getRHS()) { Out << " .. "; - RHS->printPretty(Out, 0, PrintingPolicy(LO)); + RHS->printPretty(Out, nullptr, PrintingPolicy(LO)); } Out << ":"; @@ -2411,10 +2485,11 @@ struct DOTGraphTraits<ExplodedNode*> : default: { const Stmt *S = Loc.castAs<StmtPoint>().getStmt(); + assert(S != nullptr && "Expecting non-null Stmt"); Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); + S->printPretty(Out, nullptr, PrintingPolicy(LO)); printLocation(Out, S->getLocStart()); if (Loc.getAs<PreStmt>()) @@ -2452,7 +2527,7 @@ struct DOTGraphTraits<ExplodedNode*> : } ProgramStateRef state = N->getState(); - Out << "\\|StateID: " << (const void*) state.getPtr() + Out << "\\|StateID: " << (const void*) state.get() << " NodeID: " << (const void*) N << "\\|"; state->printDOT(Out); @@ -2504,8 +2579,8 @@ void ExprEngine::ViewGraph(bool trim) { llvm::ViewGraph(*G.roots_begin(), "ExprEngine"); - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; + GraphPrintCheckerState = nullptr; + GraphPrintSourceManager = nullptr; } #endif } @@ -2515,14 +2590,14 @@ void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { GraphPrintCheckerState = this; GraphPrintSourceManager = &getContext().getSourceManager(); - OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes)); + std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes)); if (!TrimmedG.get()) llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; else llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine"); - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; + GraphPrintCheckerState = nullptr; + GraphPrintSourceManager = nullptr; #endif } |