[PATCH] D71371: [analyzer] Do not cache out on some shared implicit AST nodes.

Gábor Horváth via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 11 11:28:44 PST 2019


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);


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D71371.233423.patch
Type: text/x-patch
Size: 3350 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20191211/ba8683a1/attachment-0001.bin>


More information about the cfe-commits mailing list