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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits