danielmarjamaki updated this revision to Diff 117956. danielmarjamaki added a comment. Herald added a subscriber: szepet.
Fixes according to review comments. Reuse ast matchers in LoopUnrolling.cpp. Avoid some recursion (however the isChanged() is still recursive but it is very small and simple). Repository: rL LLVM https://reviews.llvm.org/D37897 Files: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/LoopUnrolling.cpp test/Analysis/global-vars.c
Index: test/Analysis/global-vars.c =================================================================== --- test/Analysis/global-vars.c +++ test/Analysis/global-vars.c @@ -0,0 +1,18 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha,core -verify %s + +// Avoid false positive. +static char *allv[] = {"rpcgen", "-s", "udp", "-s", "tcp"}; +static int allc = sizeof(allv) / sizeof(allv[0]); +static void falsePositive1(void) { + int i; + for (i = 1; i < allc; i++) { + const char *p = allv[i]; // no-warning + i++; + } +} + +// Detect division by zero. +static int zero = 0; +void truePositive1() { + int x = 1000 / zero; // expected-warning{{Division by zero}} +} Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -99,7 +99,10 @@ declRefExpr(to(varDecl(VarNodeMatcher)))))), binaryOperator(anyOf(hasOperatorName("="), hasOperatorName("+="), hasOperatorName("/="), hasOperatorName("*="), - hasOperatorName("-=")), + hasOperatorName("-="), hasOperatorName("%="), + hasOperatorName("<<="), hasOperatorName(">>="), + hasOperatorName("&="), hasOperatorName("|="), + hasOperatorName("^=")), hasLHS(ignoringParenImpCasts( declRefExpr(to(varDecl(VarNodeMatcher))))))); } @@ -283,5 +286,16 @@ return false; return true; } + +bool isVarChanged(const FunctionDecl *FD, const VarDecl *VD) { + if (!FD->getBody()) + return false; + auto Match = match( + stmt(hasDescendant(stmt(anyOf( + callByRef(equalsNode(VD)), getAddrTo(equalsNode(VD)), + assignedToRef(equalsNode(VD)), changeIntBoundNode(equalsNode(VD)))))), + *FD->getBody(), FD->getASTContext()); + return !Match.empty(); } -} +} // namespace ento +} // namespace clang Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -103,8 +103,86 @@ // Utility methods. //===----------------------------------------------------------------------===// +static bool isChanged(const Decl *D, const VarDecl *VD) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + return isVarChanged(FD, VD); + } + if (const auto *Rec = dyn_cast<TagDecl>(D)) { + for (const auto *RecChild : Rec->decls()) { + if (isChanged(RecChild, VD)) + return true; + } + } + return false; +} + +/** Get initial state for global static variable */ +ProgramStateRef ExprEngine::getInitialStateForGlobalStaticVar( + const LocationContext *LCtx, ProgramStateRef State, const VarDecl *VD) { + // Is variable changed anywhere in TU? + for (const Decl *D : AMgr.getASTContext().getTranslationUnitDecl()->decls()) { + if (isChanged(D, VD)) + return State; + } + + // What is the initialized value? + llvm::APSInt InitVal; + if (const Expr *I = VD->getInit()) { + if (!I->EvaluateAsInt(InitVal, getContext())) + return State; + } else { + InitVal = 0; + } + + const MemRegion *R = State->getRegion(VD, LCtx); + if (!R) + return State; + SVal V = State->getSVal(loc::MemRegionVal(R)); + SVal Constraint_untested = + evalBinOp(State, BO_EQ, V, svalBuilder.makeIntVal(InitVal), + svalBuilder.getConditionType()); + Optional<DefinedOrUnknownSVal> Constraint = + Constraint_untested.getAs<DefinedOrUnknownSVal>(); + if (!Constraint) + return State; + return State->assume(*Constraint, true); +} + +static void getGlobalStaticVars(const Stmt *FuncBody, + llvm::SmallSet<const VarDecl *, 4> *Vars) { + std::stack<const Stmt *> Children; + Children.push(FuncBody); + while (!Children.empty()) { + const Stmt *Child = Children.top(); + Children.pop(); + if (!Child) + continue; + for (const Stmt *C : Child->children()) { + Children.push(C); + } + if (const DeclRefExpr *D = dyn_cast<DeclRefExpr>(Child)) { + const VarDecl *VD = dyn_cast<VarDecl>(D->getDecl()); + if (VD && VD->isDefinedOutsideFunctionOrMethod() && + VD->getType()->isIntegerType() && + VD->getStorageClass() == SC_Static && + !VD->getType()->isPointerType()) { + Vars->insert(VD); + } + } + } +} + ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { ProgramStateRef state = StateMgr.getInitialState(InitLoc); + // Get initial states for static global variables. + if (const auto *FD = dyn_cast<FunctionDecl>(InitLoc->getDecl())) { + llvm::SmallSet<const VarDecl *, 4> Vars; + getGlobalStaticVars(FD->getBody(), &Vars); + for (const VarDecl *VD : Vars) { + state = getInitialStateForGlobalStaticVar(InitLoc, state, VD); + } + } + const Decl *D = InitLoc->getDecl(); // Preconditions. Index: include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h @@ -44,6 +44,8 @@ /// element of the stack of loops. ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State); +bool isVarChanged(const FunctionDecl *FD, const VarDecl *VD); + } // end namespace ento } // end namespace clang Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -575,15 +575,17 @@ /// \brief Default implementation of call evaluation. void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, const CallEvent &Call); + private: + ProgramStateRef getInitialStateForGlobalStaticVar(const LocationContext *LCtx, + const ProgramStateRef State, + const VarDecl *VD); + void evalLoadCommon(ExplodedNodeSet &Dst, - const Expr *NodeEx, /* Eventually will be a CFGStmt */ - const Expr *BoundEx, - ExplodedNode *Pred, - ProgramStateRef St, - SVal location, - const ProgramPointTag *tag, - QualType LoadTy); + const Expr *NodeEx, /* Eventually will be a CFGStmt */ + const Expr *BoundEx, ExplodedNode *Pred, + ProgramStateRef St, SVal location, + const ProgramPointTag *tag, QualType LoadTy); // FIXME: 'tag' should be removed, and a LocationContext should be used // instead.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits