From 79d73044b7d0adfbd18ee34285395e1d5135f662 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Thu, 2 Sep 2010 00:56:20 +0000 Subject: [PATCH] For GRExprEngine::EvalBind() (and called visitors), unifiy StoreE and AssignE. Now StoreE (const Stmt*) represents the expression where the store took place, which is the assignment expression if it takes place in an assignment. This removes some conceptual dissidence as well as removes an extra parameter from the Checker::PreVisitBind() visitor. It also improves ranges and source location information in analyzer diagnostics. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112789 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Checker/PathSensitive/Checker.h | 7 ++-- .../Checker/PathSensitive/GRExprEngine.h | 10 ++--- lib/Checker/GRExprEngine.cpp | 37 +++++++++++-------- lib/Checker/MallocChecker.cpp | 6 +-- lib/Checker/UndefinedAssignmentChecker.cpp | 12 +++--- test/Analysis/plist-output.m | 2 +- 6 files changed, 36 insertions(+), 38 deletions(-) diff --git a/include/clang/Checker/PathSensitive/Checker.h b/include/clang/Checker/PathSensitive/Checker.h index af28fc3ca7..136a29da5f 100644 --- a/include/clang/Checker/PathSensitive/Checker.h +++ b/include/clang/Checker/PathSensitive/Checker.h @@ -226,7 +226,6 @@ private: // FIXME: Remove the 'tag' option. void GR_VisitBind(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, GRExprEngine &Eng, - const Stmt *AssignE, const Stmt *StoreE, ExplodedNode *Pred, void *tag, SVal location, SVal val, bool isPrevisit) { @@ -234,7 +233,7 @@ private: isPrevisit ? ProgramPoint::PreStmtKind : ProgramPoint::PostStmtKind, 0, StoreE); assert(isPrevisit && "Only previsit supported for now."); - PreVisitBind(C, AssignE, StoreE, location, val); + PreVisitBind(C, StoreE, location, val); } // FIXME: Remove the 'tag' option. @@ -264,8 +263,8 @@ public: virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, SVal val) {} + virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, + SVal location, SVal val) {} virtual void EvalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {} virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) {} diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h index 55dab2a8a3..5ba0b36b31 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -295,10 +295,9 @@ public: const GRState *state, ExplodedNode *Pred); - void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, - ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - SVal location, SVal val, bool isPrevisit); - + void CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, SVal location, SVal val, + bool isPrevisit); /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. @@ -494,8 +493,7 @@ protected: /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore, VisitDeclStmt, and others. - void EvalBind(ExplodedNodeSet& Dst, const Stmt *AssignE, - const Stmt* StoreE, ExplodedNode* Pred, + void EvalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, ExplodedNode* Pred, const GRState* St, SVal location, SVal Val, bool atDeclInit = false); diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index c9173aa92a..12974e999e 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -306,10 +306,9 @@ bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, // FIXME: This is largely copy-paste from CheckerVisit(). Need to // unify. -void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, - ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, - SVal location, SVal val, bool isPrevisit) { +void GRExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, SVal location, + SVal val, bool isPrevisit) { if (Checkers.empty()) { Dst.insert(Src); @@ -334,7 +333,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) - checker->GR_VisitBind(*CurrSet, *Builder, *this, AssignE, StoreE, + checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE, *NI, tag, location, val, isPrevisit); // Update which NodeSet is the current one. @@ -1816,16 +1815,15 @@ void GRExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred, /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore and (soon) VisitDeclStmt, and others. -void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, const Stmt *AssignE, - const Stmt* StoreE, ExplodedNode* Pred, - const GRState* state, SVal location, SVal Val, - bool atDeclInit) { +void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, + ExplodedNode* Pred, const GRState* state, + SVal location, SVal Val, bool atDeclInit) { // Do a previsit of the bind. ExplodedNodeSet CheckedSet, Src; Src.Add(Pred); - CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true); + CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { @@ -1858,6 +1856,10 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, const Stmt *AssignE, // The next thing to do is check if the GRTransferFuncs object wants to // update the state based on the new binding. If the GRTransferFunc object // doesn't do anything, just auto-propagate the current state. + + // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE' + // is non-NULL. Checkers typically care about + GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE, newState != state); @@ -1872,7 +1874,7 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, const Stmt *AssignE, /// @param location The location to store the value /// @param Val The value to be stored void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, const Expr *AssignE, - const Expr* StoreE, + const Expr* LocationE, ExplodedNode* Pred, const GRState* state, SVal location, SVal Val, const void *tag) { @@ -1881,7 +1883,7 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, const Expr *AssignE, // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; - EvalLocation(Tmp, StoreE, Pred, state, location, tag, false); + EvalLocation(Tmp, LocationE, Pred, state, location, tag, false); if (Tmp.empty()) return; @@ -1892,9 +1894,12 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, const Expr *AssignE, ProgramPoint::PostStoreKind); SaveAndRestore OldTag(Builder->Tag, tag); - // Proceed with the store. + // Proceed with the store. We use AssignE as the anchor for the PostStore + // ProgramPoint if it is non-NULL, and LocationE otherwise. + const Expr *StoreE = AssignE ? AssignE : LocationE; + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val); + EvalBind(Dst, StoreE, *NI, GetState(*NI), location, Val); } void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, const Expr *Ex, @@ -2701,7 +2706,7 @@ void GRExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Builder->getCurrentBlockCount()); } - EvalBind(Dst, DS, DS, *I, state, + EvalBind(Dst, DS, *I, state, loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } else { @@ -2733,7 +2738,7 @@ void GRExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S, Builder->getCurrentBlockCount()); } - EvalBind(Dst, S, S, N, state, + EvalBind(Dst, S, N, state, loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } } diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp index 3224f7bb2e..ac98c89a8d 100644 --- a/lib/Checker/MallocChecker.cpp +++ b/lib/Checker/MallocChecker.cpp @@ -82,9 +82,8 @@ public: const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption, bool *respondsToCallback); void VisitLocation(CheckerContext &C, const Stmt *S, SVal l); - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, - SVal val); + virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, + SVal location, SVal val); private: void MallocMem(CheckerContext &C, const CallExpr *CE); @@ -676,7 +675,6 @@ void MallocChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { } void MallocChecker::PreVisitBind(CheckerContext &C, - const Stmt *AssignE, const Stmt *StoreE, SVal location, SVal val) { diff --git a/lib/Checker/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp index 6cef60eaee..ccc97489e6 100644 --- a/lib/Checker/UndefinedAssignmentChecker.cpp +++ b/lib/Checker/UndefinedAssignmentChecker.cpp @@ -25,9 +25,8 @@ class UndefinedAssignmentChecker public: UndefinedAssignmentChecker() : BT(0) {} static void *getTag(); - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, - SVal val); + virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, + SVal location, SVal val); }; } @@ -41,7 +40,6 @@ void *UndefinedAssignmentChecker::getTag() { } void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, - const Stmt *AssignE, const Stmt *StoreE, SVal location, SVal val) { @@ -61,8 +59,8 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, // Generate a report for this bug. const Expr *ex = 0; - while (AssignE) { - if (const BinaryOperator *B = dyn_cast(AssignE)) { + while (StoreE) { + if (const BinaryOperator *B = dyn_cast(StoreE)) { if (B->isCompoundAssignmentOp()) { const GRState *state = C.getState(); if (state->getSVal(B->getLHS()).isUndef()) { @@ -77,7 +75,7 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, break; } - if (const DeclStmt *DS = dyn_cast(AssignE)) { + if (const DeclStmt *DS = dyn_cast(StoreE)) { const VarDecl* VD = dyn_cast(DS->getSingleDecl()); ex = VD->getInit(); } diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m index aa866de03c..95faa06a06 100644 --- a/test/Analysis/plist-output.m +++ b/test/Analysis/plist-output.m @@ -205,7 +205,7 @@ void test_null_field(void) { // CHECK: // CHECK: // CHECK: line10 -// CHECK: col3 +// CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -- 2.40.0