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

Track modification of global static variables in CallGraph construction


Repository:
  rL LLVM

https://reviews.llvm.org/D37897

Files:
  include/clang/AST/Decl.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  lib/AST/Decl.cpp
  lib/Analysis/CallGraph.cpp
  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,71 @@
 // Utility methods.
 //===----------------------------------------------------------------------===//
 
+/** Get initial state for global static variable */
+ProgramStateRef ExprEngine::getInitialStateForGlobalStaticVar(
+    const LocationContext *LCtx, ProgramStateRef State, const VarDecl *VD) {
+  // Is variable changed anywhere in TU?
+  if (VD->isModified())
+    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: lib/Analysis/CallGraph.cpp
===================================================================
--- lib/Analysis/CallGraph.cpp
+++ lib/Analysis/CallGraph.cpp
@@ -33,10 +33,12 @@
   CallGraphNode *CallerNode;
 
 public:
-  CGBuilder(CallGraph *g, CallGraphNode *N)
-    : G(g), CallerNode(N) {}
+  CGBuilder(CallGraph *g, CallGraphNode *N) : G(g), CallerNode(N) {}
 
-  void VisitStmt(Stmt *S) { VisitChildren(S); }
+  void VisitStmt(Stmt *S) {
+    markModifiedVars(S);
+    VisitChildren(S);
+  }
 
   Decl *getDeclFromCall(CallExpr *CE) {
     if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
@@ -63,13 +65,14 @@
     if (Decl *D = getDeclFromCall(CE))
       addCalledDecl(D);
     VisitChildren(CE);
+    markModifiedVars(CE);
   }
 
   // Adds may-call edges for the ObjC message sends.
   void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
     if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
       Selector Sel = ME->getSelector();
-      
+
       // Find the callee definition within the same translation unit.
       Decl *D = nullptr;
       if (ME->isInstanceMessage())
@@ -88,6 +91,53 @@
       if (SubStmt)
         this->Visit(SubStmt);
   }
+
+  void modifyVar(Expr *E) {
+    auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
+    if (!D)
+      return;
+    VarDecl *VD = dyn_cast<VarDecl>(D->getDecl());
+    if (VD)
+      VD->setModified();
+  }
+
+  void markModifiedVars(Stmt *S) {
+    // Increment/Decrement, taking address of variable
+    if (UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
+      const UnaryOperatorKind K = U->getOpcode();
+      if (K == UO_AddrOf || K == UO_PostDec || K == UO_PostInc ||
+          K == UO_PreDec || K == UO_PreInc)
+        modifyVar(U->getSubExpr());
+      return;
+    }
+
+    // Assignments
+    if (BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
+      if (!B->isAssignmentOp())
+        return;
+      modifyVar(B->getLHS());
+      if (B->getLHS()->getType()->isReferenceType())
+        modifyVar(B->getRHS());
+      return;
+    }
+
+    // Handle reference arguments
+    if (auto *CE = dyn_cast<CallExpr>(S)) {
+      const Decl *D = CE->getCalleeDecl();
+      if (!D)
+        return;
+      const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+      if (!FD)
+        return;
+      unsigned N = 0;
+      for (const auto Arg : FD->parameters()) {
+        if (Arg->getType()->isReferenceType() &&
+            !Arg->getType().isConstQualified() && N < CE->getNumArgs())
+          modifyVar(CE->getArg(N));
+        N++;
+      }
+    }
+  }
 };
 
 } // end anonymous namespace
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1840,10 +1840,12 @@
   // Everything else is implicitly initialized to false.
 }
 
-VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
-                         SourceLocation StartL, SourceLocation IdL,
-                         IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
-                         StorageClass S) {
+void VarDecl::setModified() { VarDeclBits.Modified = true; }
+bool VarDecl::isModified() const { return VarDeclBits.Modified; }
+
+VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL,
+                         SourceLocation IdL, IdentifierInfo *Id, QualType T,
+                         TypeSourceInfo *TInfo, StorageClass S) {
   return new (C, DC) VarDecl(Var, C, DC, StartL, IdL, Id, T, TInfo, S);
 }
 
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.
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -790,6 +790,9 @@
     TLS_Dynamic ///< TLS with a dynamic initializer.
   };
 
+  void setModified();
+  bool isModified() const;
+
 protected:
   // A pointer union of Stmt * and EvaluatedStmt *. When an EvaluatedStmt, we
   // have allocated the auxiliary struct of information there.
@@ -812,8 +815,9 @@
     unsigned SClass : 3;
     unsigned TSCSpec : 2;
     unsigned InitStyle : 2;
+    unsigned Modified : 1;
   };
-  enum { NumVarDeclBits = 7 };
+  enum { NumVarDeclBits = 8 };
 
   friend class ASTDeclReader;
   friend class StmtIteratorBase;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to