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)] _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits