[clang] 9fdcae7 - [analyzer] Do not cache out on some shared implicit AST nodes

Gabor Horvath via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 11 17:16:22 PST 2019


Author: Gabor Horvath
Date: 2019-12-11T17:15:12-08:00
New Revision: 9fdcae7c81f5ff92ad694f5d993a042a525fd6bc

URL: https://github.com/llvm/llvm-project/commit/9fdcae7c81f5ff92ad694f5d993a042a525fd6bc
DIFF: https://github.com/llvm/llvm-project/commit/9fdcae7c81f5ff92ad694f5d993a042a525fd6bc.diff

LOG: [analyzer] Do not cache out on some shared implicit AST nodes

Some AST nodes which 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.
Since these nodes do not really require any processing from the analyzer
we just omit them from the CFG.

Differential Revision: https://reviews.llvm.org/D71371

Added: 
    clang/test/Analysis/designated-initializer-values.c

Modified: 
    clang/include/clang/Analysis/CFG.h
    clang/lib/Analysis/CFG.cpp
    clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
    clang/test/Analysis/designated-initializer.c
    clang/test/Analysis/initializers-cfg-output.cpp
    clang/test/Analysis/temp-obj-dtors-cfg-output.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index a8301a0e0063..ea3d8b2921a7 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -1251,6 +1251,7 @@ class CFG {
     bool AddRichCXXConstructors = false;
     bool MarkElidedCXXConstructors = false;
     bool AddVirtualBaseBranches = false;
+    bool OmitImplicitValueInitializers = false;
 
     BuildOptions() = default;
 

diff  --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index bc21d1c9076d..e10bfd805933 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -2135,6 +2135,11 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
     default:
       return VisitStmt(S, asc);
 
+    case Stmt::ImplicitValueInitExprClass:
+      if (BuildOpts.OmitImplicitValueInitializers)
+        return Block;
+      return VisitStmt(S, asc);
+
     case Stmt::AddrLabelExprClass:
       return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
 

diff  --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 73e1a0d0000f..94fc09e64aa0 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -43,6 +43,7 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx,
       CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr),
       options(Options) {
   AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
+  AnaCtxMgr.getCFGBuildOptions().OmitImplicitValueInitializers = true;
 }
 
 AnalysisManager::~AnalysisManager() {

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 2a23d1cae7b5..f917a4c8637b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1321,6 +1321,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::WhileStmtClass:
     case Expr::MSDependentExistsStmtClass:
       llvm_unreachable("Stmt should not be in analyzer evaluation loop");
+    case Stmt::ImplicitValueInitExprClass:
+      // These nodes are shared in the CFG and would case caching out.
+      // Moreover, no additional evaluation required for them, the
+      // analyzer can reconstruct these values from the AST.
+      llvm_unreachable("Should be pruned from CFG");
 
     case Stmt::ObjCSubscriptRefExprClass:
     case Stmt::ObjCPropertyRefExprClass:
@@ -1391,7 +1396,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::IntegerLiteralClass:
     case Stmt::FixedPointLiteralClass:
     case Stmt::CharacterLiteralClass:
-    case Stmt::ImplicitValueInitExprClass:
     case Stmt::CXXScalarValueInitExprClass:
     case Stmt::CXXBoolLiteralExprClass:
     case Stmt::ObjCBoolLiteralExprClass:

diff  --git a/clang/test/Analysis/designated-initializer-values.c b/clang/test/Analysis/designated-initializer-values.c
new file mode 100644
index 000000000000..1efc10aece60
--- /dev/null
+++ b/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}}
+}

diff  --git a/clang/test/Analysis/designated-initializer.c b/clang/test/Analysis/designated-initializer.c
index 920b2f08d7e7..adca0ab6c875 100644
--- a/clang/test/Analysis/designated-initializer.c
+++ b/clang/test/Analysis/designated-initializer.c
@@ -31,11 +31,10 @@ void test() {
 // CHECK:  11: struct LUQ var = {getUQ(), .uq.q.a = 100};
 // CHECK:  12: 1
 // CHECK:  13: 2
-// CHECK:  14: /*implicit*/(int)0
-// CHECK:  15: {[B1.12], [B1.13]}
+// CHECK:  14: {[B1.12], [B1.13]}
+// CHECK:  17: /*no init*/
 // CHECK:  18: /*no init*/
-// CHECK:  19: /*no init*/
-// CHECK:  20: 3
-// CHECK:  21: {[B1.18], [B1.19], [B1.20]}
-// CHECK:  22: {/*base*/[B1.17], /*updater*/[B1.21]} 
-// CHECK:  24: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3};
+// CHECK:  19: 3
+// CHECK:  20: {[B1.17], [B1.18], [B1.19]}
+// CHECK:  21: {/*base*/[B1.16], /*updater*/[B1.20]} 
+// CHECK:  23: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3};

diff  --git a/clang/test/Analysis/initializers-cfg-output.cpp b/clang/test/Analysis/initializers-cfg-output.cpp
index f83386492656..14c1b1e99a41 100644
--- a/clang/test/Analysis/initializers-cfg-output.cpp
+++ b/clang/test/Analysis/initializers-cfg-output.cpp
@@ -126,14 +126,13 @@ class TestOrder : public C, public B, public A {
 // WARNINGS-NEXT:     5:  (CXXConstructExpr, class A)
 // ANALYZER-NEXT:     5:  (CXXConstructExpr, A() (Base initializer), class A)
 // CHECK-NEXT:     6: A([B1.5]) (Base initializer)
-// CHECK-NEXT:     7: /*implicit*/(int)0
-// CHECK-NEXT:     8: i([B1.7]) (Member initializer)
-// CHECK-NEXT:     9: this
-// CHECK-NEXT:    10: [B1.9]->i
-// CHECK-NEXT:    11: r([B1.10]) (Member initializer)
-// WARNINGS-NEXT:    12:  (CXXConstructExpr, class A)
-// ANALYZER-NEXT:    12:  (CXXConstructExpr, [B1.13], class A)
-// CHECK-NEXT:    13: A a;
+// CHECK-NEXT:     7: i(/*implicit*/(int)0) (Member initializer)
+// CHECK-NEXT:     8: this
+// CHECK-NEXT:    9: [B1.8]->i
+// CHECK-NEXT:    10: r([B1.9]) (Member initializer)
+// WARNINGS-NEXT:    11:  (CXXConstructExpr, class A)
+// ANALYZER-NEXT:    11:  (CXXConstructExpr, [B1.12], class A)
+// CHECK-NEXT:    12: A a;
 // CHECK-NEXT:     Preds (2): B2 B3
 // CHECK-NEXT:     Succs (1): B0
 // CHECK:        [B2]

diff  --git a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
index d08b01cd3964..5b16915ae6f6 100644
--- a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -1224,8 +1224,7 @@ const C &bar3(bool coin) {
 // CHECK:    16: a([B1.15]) (Member initializer)
 // CHECK:    17: ~B() (Temporary object destructor)
 // CHECK:    18: ~A() (Temporary object destructor)
-// CHECK:    19: /*implicit*/(int)0
-// CHECK:    20: b([B1.19]) (Member initializer)
+// CHECK:    19: b(/*implicit*/(int)0) (Member initializer)
 // CHECK:     Preds (1): B2
 // CHECK:     Succs (1): B0
 // CHECK:   [B0 (EXIT)]


        


More information about the cfe-commits mailing list