xazax.hun created this revision.
xazax.hun added reviewers: NoQ, dcoughlin, Szelethus, baloghadamsoftware, 
haowei.
xazax.hun added a project: clang.
Herald added subscribers: Charusso, gamesh411, dkrupp, donat.nagy, 
mikhail.ramalho, a.sidorin, rnkovacs, szepet.

Some AST nodes that stands for implicit initialization is shared. The analyzer 
will do the same evaluation on the same nodes resulting in the same state. The 
analyzer will "cache out", i.e. it thinks that it visited an already existing 
node in the exploded graph. This is not true in this case and we lose coverage. 
This patch introduces a trick that prevents caching out.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D71371

Files:
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/test/Analysis/designated-initializer-values.c


Index: clang/test/Analysis/designated-initializer-values.c
===================================================================
--- /dev/null
+++ clang/test/Analysis/designated-initializer-values.c
@@ -0,0 +1,38 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection 
-std=c99 -verify %s
+
+void clang_analyzer_eval(int);
+
+void array_init() {
+  int a[5] = {[4] = 29, [2] = 15, [0] = 4};
+  clang_analyzer_eval(a[0] == 4);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[1] == 0);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[2] == 15); // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[3] == 0);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[4] == 29); // expected-warning{{TRUE}}
+  int b[5] = {[0 ... 2] = 1, [4] = 5};
+  clang_analyzer_eval(b[0] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[1] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[2] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[3] == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[4] == 5); // expected-warning{{TRUE}}
+}
+
+struct point {
+  int x, y;
+};
+
+void struct_init() {
+  struct point p = {.y = 5, .x = 3};
+  clang_analyzer_eval(p.x == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(p.y == 5); // expected-warning{{TRUE}}
+}
+
+void array_of_struct() {
+  struct point ptarray[3] = { [2].y = 1, [2].x = 2, [0].x = 3 };
+  clang_analyzer_eval(ptarray[0].x == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[0].y == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[1].x == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[1].y == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[2].x == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[2].y == 1); // expected-warning{{TRUE}}
+}
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -193,6 +193,11 @@
 REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction,
                                  ObjectsUnderConstructionMap)
 
+// The AST sometimes ends up sharing nodes for compile time constants.
+// We might end up caching out on those notes, this trait intended to
+// prevent that explicitly.
+REGISTER_MAP_WITH_PROGRAMSTATE(NoCachingOutForConsts, const Stmt *, unsigned 
long)
+
 
//===----------------------------------------------------------------------===//
 // Engine construction and deletion.
 
//===----------------------------------------------------------------------===//
@@ -1403,6 +1408,13 @@
     case Stmt::OMPArraySectionExprClass:
     case Stmt::TypeTraitExprClass: {
       Bldr.takeNodes(Pred);
+      if (isa<ImplicitValueInitExpr>(S)) {
+        ProgramStateRef State = Pred->getState();
+        const unsigned long *Count = State->get<NoCachingOutForConsts>(0);
+        State = State->set<NoCachingOutForConsts>(0, Count? *Count + 1 : 0);
+        Pred = Bldr.generateNode(S, Pred, State);
+        assert(Pred && "We should never cache out on constants");
+      }
       ExplodedNodeSet preVisit;
       getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
       getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this);


Index: clang/test/Analysis/designated-initializer-values.c
===================================================================
--- /dev/null
+++ clang/test/Analysis/designated-initializer-values.c
@@ -0,0 +1,38 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c99 -verify %s
+
+void clang_analyzer_eval(int);
+
+void array_init() {
+  int a[5] = {[4] = 29, [2] = 15, [0] = 4};
+  clang_analyzer_eval(a[0] == 4);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[1] == 0);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[2] == 15); // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[3] == 0);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(a[4] == 29); // expected-warning{{TRUE}}
+  int b[5] = {[0 ... 2] = 1, [4] = 5};
+  clang_analyzer_eval(b[0] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[1] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[2] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[3] == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(b[4] == 5); // expected-warning{{TRUE}}
+}
+
+struct point {
+  int x, y;
+};
+
+void struct_init() {
+  struct point p = {.y = 5, .x = 3};
+  clang_analyzer_eval(p.x == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(p.y == 5); // expected-warning{{TRUE}}
+}
+
+void array_of_struct() {
+  struct point ptarray[3] = { [2].y = 1, [2].x = 2, [0].x = 3 };
+  clang_analyzer_eval(ptarray[0].x == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[0].y == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[1].x == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[1].y == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[2].x == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptarray[2].y == 1); // expected-warning{{TRUE}}
+}
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -193,6 +193,11 @@
 REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction,
                                  ObjectsUnderConstructionMap)
 
+// The AST sometimes ends up sharing nodes for compile time constants.
+// We might end up caching out on those notes, this trait intended to
+// prevent that explicitly.
+REGISTER_MAP_WITH_PROGRAMSTATE(NoCachingOutForConsts, const Stmt *, unsigned long)
+
 //===----------------------------------------------------------------------===//
 // Engine construction and deletion.
 //===----------------------------------------------------------------------===//
@@ -1403,6 +1408,13 @@
     case Stmt::OMPArraySectionExprClass:
     case Stmt::TypeTraitExprClass: {
       Bldr.takeNodes(Pred);
+      if (isa<ImplicitValueInitExpr>(S)) {
+        ProgramStateRef State = Pred->getState();
+        const unsigned long *Count = State->get<NoCachingOutForConsts>(0);
+        State = State->set<NoCachingOutForConsts>(0, Count? *Count + 1 : 0);
+        Pred = Bldr.generateNode(S, Pred, State);
+        assert(Pred && "We should never cache out on constants");
+      }
       ExplodedNodeSet preVisit;
       getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
       getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to