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

Reply via email to