forked from OSchip/llvm-project
[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
This commit is contained in:
parent
83e1bd36be
commit
9fdcae7c81
|
@ -1251,6 +1251,7 @@ public:
|
|||
bool AddRichCXXConstructors = false;
|
||||
bool MarkElidedCXXConstructors = false;
|
||||
bool AddVirtualBaseBranches = false;
|
||||
bool OmitImplicitValueInitializers = false;
|
||||
|
||||
BuildOptions() = default;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx,
|
|||
CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr),
|
||||
options(Options) {
|
||||
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
|
||||
AnaCtxMgr.getCFGBuildOptions().OmitImplicitValueInitializers = true;
|
||||
}
|
||||
|
||||
AnalysisManager::~AnalysisManager() {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}}
|
||||
}
|
|
@ -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};
|
||||
|
|
|
@ -126,14 +126,13 @@ public:
|
|||
// 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]
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue