diff options
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h | 40 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h | 49 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp | 6 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 2 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 47 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineC.cpp | 5 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineObjC.cpp | 4 |
7 files changed, 82 insertions, 71 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index 8c8e82ce20..95974d1768 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -144,20 +144,15 @@ public: /// \brief Generates a new transition in the program state graph /// (ExplodedGraph). Uses the default CheckerContext predecessor node. /// - /// @param State The state of the generated node. + /// @param State The state of the generated node. If not specified, the state + /// will not be changed, but the new node will have the checker's tag. /// @param Tag The tag is used to uniquely identify the creation site. If no /// tag is specified, a default tag, unique to the given checker, /// will be used. Tags are used to prevent states generated at /// different sites from caching out. - ExplodedNode *addTransition(ProgramStateRef State, + ExplodedNode *addTransition(ProgramStateRef State = 0, const ProgramPointTag *Tag = 0) { - return addTransitionImpl(State, false, 0, Tag); - } - - /// \brief Generates a default transition (containing checker tag but no - /// checker state changes). - ExplodedNode *addTransition() { - return addTransition(getState()); + return addTransitionImpl(State ? State : getState(), false, 0, Tag); } /// \brief Generates a new transition with the given predecessor. @@ -170,16 +165,17 @@ public: /// @param IsSink Mark the new node as sink, which will stop exploration of /// the given path. ExplodedNode *addTransition(ProgramStateRef State, - ExplodedNode *Pred, - const ProgramPointTag *Tag = 0, - bool IsSink = false) { - return addTransitionImpl(State, IsSink, Pred, Tag); + ExplodedNode *Pred, + const ProgramPointTag *Tag = 0) { + return addTransitionImpl(State, false, Pred, Tag); } - /// \brief Generate a sink node. Generating sink stops exploration of the + /// \brief Generate a sink node. Generating a sink stops exploration of the /// given path. - ExplodedNode *generateSink(ProgramStateRef state = 0) { - return addTransitionImpl(state ? state : getState(), true); + ExplodedNode *generateSink(ProgramStateRef State = 0, + ExplodedNode *Pred = 0, + const ProgramPointTag *Tag = 0) { + return addTransitionImpl(State ? State : getState(), true, Pred, Tag); } /// \brief Emit the diagnostics report. @@ -226,9 +222,15 @@ private: return Pred; Changed = true; - ExplodedNode *node = NB.generateNode(Tag ? Location.withTag(Tag) : Location, - State, - P ? P : Pred, MarkAsSink); + const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); + if (!P) + P = Pred; + + ExplodedNode *node; + if (MarkAsSink) + node = NB.generateSink(LocalLoc, State, P); + else + node = NB.generateNode(LocalLoc, State, P); return node; } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index e75cdd8759..16bd45c538 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -265,14 +265,21 @@ public: virtual ~NodeBuilder() {} /// \brief Generates a node in the ExplodedGraph. + ExplodedNode *generateNode(const ProgramPoint &PP, + ProgramStateRef State, + ExplodedNode *Pred) { + return generateNodeImpl(PP, State, Pred, false); + } + + /// \brief Generates a sink in the ExplodedGraph. /// /// When a node is marked as sink, the exploration from the node is stopped - - /// the node becomes the last node on the path. - ExplodedNode *generateNode(const ProgramPoint &PP, + /// the node becomes the last node on the path and certain kinds of bugs are + /// suppressed. + ExplodedNode *generateSink(const ProgramPoint &PP, ProgramStateRef State, - ExplodedNode *Pred, - bool MarkAsSink = false) { - return generateNodeImpl(PP, State, Pred, MarkAsSink); + ExplodedNode *Pred) { + return generateNodeImpl(PP, State, Pred, true); } const ExplodedNodeSet &getResults() { @@ -317,13 +324,18 @@ public: NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet, const NodeBuilderContext &Ctx, ProgramPoint &L) : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} + ExplodedNode *generateNode(ProgramStateRef State, ExplodedNode *Pred, - const ProgramPointTag *Tag = 0, - bool MarkAsSink = false) { - ProgramPoint LocalLoc = (Tag ? Location.withTag(Tag): Location); + const ProgramPointTag *Tag = 0) { + const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); + return NodeBuilder::generateNode(LocalLoc, State, Pred); + } - ExplodedNode *N = generateNodeImpl(LocalLoc, State, Pred, MarkAsSink); + ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, + const ProgramPointTag *Tag = 0) { + const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); + ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred); if (N && N->isSink()) sinksGenerated.push_back(N); return N; @@ -336,7 +348,7 @@ public: /// \class StmtNodeBuilder /// \brief This builder class is useful for generating nodes that resulted from -/// visiting a statement. The main difference from it's parent NodeBuilder is +/// visiting a statement. The main difference from its parent NodeBuilder is /// that it creates a statement specific ProgramPoint. class StmtNodeBuilder: public NodeBuilder { NodeBuilder *EnclosingBldr; @@ -363,22 +375,27 @@ public: virtual ~StmtNodeBuilder(); + using NodeBuilder::generateNode; + using NodeBuilder::generateSink; + ExplodedNode *generateNode(const Stmt *S, ExplodedNode *Pred, ProgramStateRef St, - bool MarkAsSink = false, const ProgramPointTag *tag = 0, ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, Pred->getLocationContext(), tag); - return generateNodeImpl(L, St, Pred, MarkAsSink); + return NodeBuilder::generateNode(L, St, Pred); } - ExplodedNode *generateNode(const ProgramPoint &PP, + ExplodedNode *generateSink(const Stmt *S, ExplodedNode *Pred, - ProgramStateRef State, - bool MarkAsSink = false) { - return generateNodeImpl(PP, State, Pred, MarkAsSink); + ProgramStateRef St, + const ProgramPointTag *tag = 0, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), tag); + return NodeBuilder::generateSink(L, St, Pred); } }; diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp index 7b724d2be9..81e4f0dcf2 100644 --- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp @@ -192,8 +192,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE, QualType T = CE->getType(); if (!T->isVoidType()) Res = Eng.getSValBuilder().makeTruthVal(true, T); - B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res), - false, this); + B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res), this); } } @@ -205,8 +204,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE, if (!T->isVoidType()) Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType()); StmtNodeBuilder B(N, Dst, Eng.getBuilderContext()); - B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res), - false, this); + B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res), this); } } diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 7c20ce70bd..73b6b61e31 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -3432,7 +3432,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, V = V ^ RefVal::ErrorOverAutorelease; state = setRefBinding(state, Sym, V); - ExplodedNode *N = Ctx.addTransition(state, Pred, Tag, /*IsSink=*/true); + ExplodedNode *N = Ctx.generateSink(state, Pred, Tag); if (N) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index c64a35eafb..d7666829d5 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -277,7 +277,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // up. Since no symbols are dead, we can optimize and not clean out // the constraint manager. StmtNodeBuilder Bldr(Pred, Out, *currentBuilderContext); - Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, false, &cleanupTag,K); + Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, &cleanupTag, K); } else { // Call checkers with the non-cleaned state so that they could query the @@ -309,8 +309,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // generate a transition to that state. ProgramStateRef CleanedCheckerSt = StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState); - Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, false, - &cleanupTag, K); + Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, &cleanupTag, K); } } } @@ -525,8 +524,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SEHExceptStmtClass: case Stmt::LambdaExprClass: case Stmt::SEHFinallyStmtClass: { - const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState(), - /* sink */ true); + const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); Engine.addAbortedBlock(node, currentBuilderContext->getBlock()); break; } @@ -885,7 +883,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXThrowExprClass: // FIXME: This is not complete. We basically treat @throw as // an abort. - Bldr.generateNode(S, Pred, Pred->getState(), /*IsSink=*/true); + Bldr.generateSink(S, Pred, Pred->getState()); break; case Stmt::ReturnStmtClass: @@ -1033,7 +1031,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, if (nodeBuilder.getContext().getCurrentBlockCount() >= AMgr.getMaxVisit()) { static SimpleProgramPointTag tag("ExprEngine : Block count exceeded"); const ExplodedNode *Sink = - nodeBuilder.generateNode(pred->getState(), pred, &tag, true); + nodeBuilder.generateSink(pred->getState(), pred, &tag); // Check if we stopped at the top level function or not. // Root node should have the location context of the top most function. @@ -1417,7 +1415,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, ProgramPoint::PostLValueKind); return; } @@ -1429,19 +1427,18 @@ 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), false, 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, ProgramPoint::PostLValueKind); return; } if (isa<FieldDecl>(D)) { - // FIXME: Compute lvalue of fields. - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, UnknownVal()), - false, 0, ProgramPoint::PostLValueKind); + // FIXME: Compute lvalue of field pointers-to-member. + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, UnknownVal()), 0, + ProgramPoint::PostLValueKind); return; } - assert (false && - "ValueDecl support for this ValueDecl not implemented."); + llvm_unreachable("Support for this Decl not implemented."); } /// VisitArraySubscriptExpr - Transfer function for array accesses @@ -1466,8 +1463,8 @@ 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), - false, 0, ProgramPoint::PostLValueKind); + Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0, + ProgramPoint::PostLValueKind); } } @@ -1530,7 +1527,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, L = UnknownVal(); } - Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), false, 0, + Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0, ProgramPoint::PostLValueKind); } else { Bldr.takeNodes(Pred); @@ -1574,7 +1571,7 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, LocReg = LocRegVal->getRegion(); const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0); - Bldr.generateNode(L, PredI, state, false); + Bldr.generateNode(L, state, PredI); } Dst.insert(TmpDst); @@ -1679,8 +1676,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, // This is important. We must nuke the old binding. Bldr.generateNode(NodeEx, *NI, state->BindExpr(BoundEx, LCtx, UnknownVal()), - false, tag, - ProgramPoint::PostLoadKind); + tag, ProgramPoint::PostLoadKind); } else { if (LoadTy.isNull()) @@ -1688,7 +1684,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, SVal V = state->getSVal(cast<Loc>(location), LoadTy); Bldr.generateNode(NodeEx, *NI, state->bindExprAndLocation(BoundEx, LCtx, location, V), - false, tag, ProgramPoint::PostLoadKind); + tag, ProgramPoint::PostLoadKind); } } } @@ -1720,9 +1716,8 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, // instead "int *p" is noted as // "Variable 'p' initialized to a null pointer value" - // FIXME: why is 'tag' not used instead of etag? - static SimpleProgramPointTag etag("ExprEngine: Location"); - Bldr.generateNode(NodeEx, Pred, state, false, &etag); + static SimpleProgramPointTag tag("ExprEngine: Location"); + Bldr.generateNode(NodeEx, Pred, state, &tag); } ExplodedNodeSet Tmp; getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, @@ -1763,14 +1758,14 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, if (ProgramStateRef StateTrue = state->assume(*SEV, true)) { SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val); - Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first); + Bldr.generateNode(Ex, Pred, StateTrue, tags.first); } // Next, assume that the condition is false. if (ProgramStateRef StateFalse = state->assume(*SEV, false)) { SVal Val = svalBuilder.makeIntVal(0U, Ex->getType()); StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val); - Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second); + Bldr.generateNode(Ex, Pred, StateFalse, tags.second); } } } diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 3e14765875..2895e26da3 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -211,8 +211,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext); Bldr.generateNode(BE, Pred, State->BindExpr(BE, Pred->getLocationContext(), V), - false, 0, - ProgramPoint::PostLValueKind); + 0, ProgramPoint::PostLValueKind); // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); @@ -347,7 +346,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (T->isReferenceType()) { // A bad_cast exception is thrown if input value is a reference. // Currently, we model this, by generating a sink. - Bldr.generateNode(CastE, Pred, state, true); + Bldr.generateSink(CastE, Pred, state); continue; } else { // If the cast fails on a pointer, bind to 0. diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index e3bc498b51..e26153893e 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -187,7 +187,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, if (Msg->getSelector() == RaiseSel) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. - Bldr.generateNode(currentStmt, Pred, State, true); + Bldr.generateSink(currentStmt, Pred, State); continue; } @@ -237,7 +237,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, if (RaisesException) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. - Bldr.generateNode(currentStmt, Pred, Pred->getState(), true); + Bldr.generateSink(currentStmt, Pred, Pred->getState()); continue; } |