summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h4
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h9
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h9
-rw-r--r--clang/lib/Analysis/CFG.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/CoreEngine.cpp18
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp28
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp19
-rw-r--r--clang/test/Analysis/analyzer-config.c4
-rw-r--r--clang/test/Analysis/analyzer-config.cpp3
10 files changed, 81 insertions, 29 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index d8a72457309..a2e211edea8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -96,6 +96,10 @@ private:
void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
ExplodedNode *Pred);
+ /// Handle conditional logic for running static initializers.
+ void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
+ ExplodedNode *Pred);
+
private:
CoreEngine(const CoreEngine &) LLVM_DELETED_FUNCTION;
void operator=(const CoreEngine &) LLVM_DELETED_FUNCTION;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 42c0c0488ef..33e4431eb4b 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -224,6 +224,15 @@ public:
const CFGBlock *DstT,
const CFGBlock *DstF);
+ /// Called by CoreEngine. Used to processing branching behavior
+ /// at static initalizers.
+ void processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF);
+
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void processIndirectGoto(IndirectGotoNodeBuilder& builder);
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 4578f6f3232..d4100634a78 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -72,6 +72,15 @@ public:
const CFGBlock *DstT,
const CFGBlock *DstF) = 0;
+ /// Called by CoreEngine. Used to processing branching behavior
+ /// at static initalizers.
+ virtual void processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) = 0;
+
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0;
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index f436ef3f6a3..91a7fdf6bcb 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1665,6 +1665,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// whether or not they are initialized.
if (Block) {
Succ = Block;
+ Block = 0;
if (badCFG)
return 0;
}
@@ -1714,15 +1715,14 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
if (ScopePos && VD == *ScopePos)
++ScopePos;
- CFGBlock *B = Block ? Block : LastBlock;
+ CFGBlock *B = LastBlock;
if (blockBeforeInit) {
Succ = B;
- Block = 0;
- CFGBlock *branchBlock = createBlock(false);
- branchBlock->setTerminator(DS);
- addSuccessor(branchBlock, blockBeforeInit);
- addSuccessor(branchBlock, B);
- B = branchBlock;
+ Block = createBlock(false);
+ Block->setTerminator(DS);
+ addSuccessor(Block, blockBeforeInit);
+ addSuccessor(Block, B);
+ B = Block;
}
return B;
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 1326d0d01b0..65faa10134d 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -238,6 +238,6 @@ bool AnalyzerOptions::shouldPrunePaths() {
}
bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
- return getBooleanOption("conditional-static-initializers", false);
+ return getBooleanOption("cfg-conditional-static-initializers", true);
}
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index c61bcf7d411..b09b2c2ddfa 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -346,6 +346,11 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
default:
llvm_unreachable("Analysis for this terminator not implemented.");
+ // Model static initializers.
+ case Stmt::DeclStmtClass:
+ HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
+ return;
+
case Stmt::BinaryOperatorClass: // '&&' and '||'
HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
return;
@@ -456,6 +461,19 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
enqueue(Dst);
}
+
+void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
+ ExplodedNode *Pred) {
+ assert(B->succ_size() == 2);
+ NodeBuilderContext Ctx(*this, B, Pred);
+ ExplodedNodeSet Dst;
+ SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
+ *(B->succ_begin()), *(B->succ_begin()+1));
+ // Enqueue the new frontier onto the worklist.
+ enqueue(Dst);
+}
+
+
void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
ExplodedNode *Pred) {
assert(B);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 8ad5a3dbdee..789abb7d863 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1344,6 +1344,34 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
currBldrCtx = 0;
}
+/// The GDM component containing the set of global variables which have been
+/// previously initialized with explicit initializers.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
+ llvm::ImmutableSet<const VarDecl *>)
+
+void ExprEngine::processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext &BuilderCtx,
+ ExplodedNode *Pred,
+ clang::ento::ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) {
+ currBldrCtx = &BuilderCtx;
+
+ const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ ProgramStateRef state = Pred->getState();
+ bool initHasRun = state->contains<InitializedGlobalsSet>(VD);
+ BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF);
+
+ if (!initHasRun) {
+ state = state->add<InitializedGlobalsSet>(VD);
+ }
+
+ builder.generateNode(state, initHasRun, Pred);
+ builder.markInfeasible(!initHasRun);
+
+ currBldrCtx = 0;
+}
+
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 2f2eb8628a0..3a3c9713dd2 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -423,11 +423,6 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV));
}
-/// The GDM component containing the set of global variables which have been
-/// previously initialized with explicit initializers.
-REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
- llvm::ImmutableSet<const VarDecl *> )
-
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
// Assumption: The CFG has one DeclStmt per Decl.
@@ -438,15 +433,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
Dst.insert(Pred);
return;
}
-
- // Check if a value has been previously initialized. There will be an entry in
- // the set for variables with global storage which have been previously
- // initialized.
- if (VD->hasGlobalStorage())
- if (Pred->getState()->contains<InitializedGlobalsSet>(VD)) {
- Dst.insert(Pred);
- return;
- }
// FIXME: all pre/post visits should eventually be handled by ::Visit().
ExplodedNodeSet dstPreVisit;
@@ -464,11 +450,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
// Note in the state that the initialization has occurred.
ExplodedNode *UpdatedN = N;
- if (VD->hasGlobalStorage()) {
- state = state->add<InitializedGlobalsSet>(VD);
- UpdatedN = B.generateNode(DS, N, state);
- }
-
SVal InitVal = state->getSVal(InitEx, LC);
if (isa<CXXConstructExpr>(InitEx->IgnoreImplicit())) {
diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index 7fa299b786e..96b948352b3 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -5,6 +5,7 @@ void bar() {}
void foo() { bar(); }
// CHECK: [config]
+// CHECK-NEXT: cfg-conditional-static-initializers = true
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -15,4 +16,5 @@ void foo() { bar(); }
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: mode = deep
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 9
+// CHECK-NEXT: num-entries = 10
+
diff --git a/clang/test/Analysis/analyzer-config.cpp b/clang/test/Analysis/analyzer-config.cpp
index 59587f6e11d..c3a04c946e7 100644
--- a/clang/test/Analysis/analyzer-config.cpp
+++ b/clang/test/Analysis/analyzer-config.cpp
@@ -14,6 +14,7 @@ public:
// CHECK-NEXT: c++-inlining = constructors
// CHECK-NEXT: c++-stdlib-inlining = true
// CHECK-NEXT: c++-template-inlining = true
+// CHECK-NEXT: cfg-conditional-static-initializers = true
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -24,4 +25,4 @@ public:
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: mode = deep
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 12
+// CHECK-NEXT: num-entries = 13
OpenPOWER on IntegriCloud