danielmarjamaki updated this revision to Diff 115385.
danielmarjamaki added a comment.

Minor cleanups. Changed names. Updated comments.


Repository:
  rL LLVM

https://reviews.llvm.org/D37897

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  lib/StaticAnalyzer/Core/ExprEngine.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/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -103,8 +103,107 @@
 // Utility methods.
 //===----------------------------------------------------------------------===//
 
+/** Recursively check if variable is changed in code. */
+static bool isChanged(const Stmt *S, const VarDecl *VD, bool Write) {
+  if (!S)
+    return false;
+  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
+    if (B->isAssignmentOp())
+      return isChanged(B->getLHS(), VD, true) ||
+             isChanged(B->getRHS(), VD, Write);
+  } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
+    // Operators that mean operand is written.
+    // AddrOf is here because the address might be used to write the operand
+    // later indirectly.
+    if (U->getOpcode() == UO_AddrOf || U->getOpcode() == UO_PreInc ||
+        U->getOpcode() == UO_PreDec || U->getOpcode() == UO_PostInc ||
+        U->getOpcode() == UO_PostDec)
+      return isChanged(U->getSubExpr(), VD, true);
+  } else if (const DeclRefExpr *D = dyn_cast<DeclRefExpr>(S)) {
+    return Write && D->getDecl() == VD;
+  }
+
+  for (const Stmt *Child : S->children()) {
+    if (isChanged(Child, VD, Write))
+      return true;
+  }
+  return false;
+}
+
+/** Is variable changed in function or method? */
+static bool isChanged(const Decl *D, const VarDecl *VD) {
+  if (isa<FunctionDecl>(D))
+    return isChanged(D->getBody(), VD, false);
+  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 *S,
+                                llvm::SmallSet<const VarDecl *, 4> *Vars) {
+  if (!S)
+    return;
+  if (const DeclRefExpr *D = dyn_cast<DeclRefExpr>(S)) {
+    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);
+    }
+  }
+  for (const Stmt *Child : S->children()) {
+    getStaticVars(Child, Vars);
+  }
+}
+
 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 = getInitialState(InitLoc, state, VD);
+    }
+  }
+
   const Decl *D = InitLoc->getDecl();
 
   // Preconditions.
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