aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2013-03-28 18:43:15 +0000
committerTed Kremenek <kremenek@apple.com>2013-03-28 18:43:15 +0000
commitfbd4b5dc7febd1d8b4fa64ab00a29d72b44bec7b (patch)
tree37ce213d499eff1f3e353c475579a0127a1f59b3
parent9fdc00a237fe19b892f22780321ddfd1a3691d61 (diff)
Add CFG logic to create a conditional branch for modeling static initializers.
This is an optional variant of the CFG. This allows analyses to model whether or not a static initializer has run, e.g.: static Foo x = bar(); For basic dataflow analysis in Sema we will just assume that the initializer always runs. For the static analyzer we can use this branch to accurately track whether or not initializers are on. This patch just adds the (opt-in) functionality to the CFG. The static analyzer still needs to be modified to adopt this feature. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178263 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Analysis/CFG.h4
-rw-r--r--lib/Analysis/CFG.cpp32
2 files changed, 34 insertions, 2 deletions
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 57f980ef4c..ee0be736dd 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -601,6 +601,7 @@ public:
bool AddInitializers;
bool AddImplicitDtors;
bool AddTemporaryDtors;
+ bool AddStaticInitBranches;
bool alwaysAdd(const Stmt *stmt) const {
return alwaysAddMask[stmt->getStmtClass()];
@@ -621,7 +622,8 @@ public:
,AddEHEdges(false)
,AddInitializers(false)
,AddImplicitDtors(false)
- ,AddTemporaryDtors(false) {}
+ ,AddTemporaryDtors(false)
+ ,AddStaticInitBranches(false) {}
};
/// \brief Provides a custom implementation of the iterator class to have the
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index f20f84c5c0..f436ef3f6a 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -1653,10 +1653,24 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
bool IsReference = false;
bool HasTemporaries = false;
+ // Guard static initializers under a branch.
+ CFGBlock *blockBeforeInit = 0;
+
// Destructors of temporaries in initialization expression should be called
// after initialization finishes.
Expr *Init = VD->getInit();
if (Init) {
+ if (BuildOpts.AddStaticInitBranches && VD->isStaticLocal()) {
+ // For static variables, we need to create a branch to track
+ // whether or not they are initialized.
+ if (Block) {
+ Succ = Block;
+ if (badCFG)
+ return 0;
+ }
+ blockBeforeInit = Succ;
+ }
+
IsReference = VD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
@@ -1700,7 +1714,18 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
if (ScopePos && VD == *ScopePos)
++ScopePos;
- return Block ? Block : LastBlock;
+ CFGBlock *B = Block ? Block : LastBlock;
+ if (blockBeforeInit) {
+ Succ = B;
+ Block = 0;
+ CFGBlock *branchBlock = createBlock(false);
+ branchBlock->setTerminator(DS);
+ addSuccessor(branchBlock, blockBeforeInit);
+ addSuccessor(branchBlock, B);
+ B = branchBlock;
+ }
+
+ return B;
}
CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
@@ -3642,6 +3667,11 @@ public:
Terminator->printPretty(OS, Helper, Policy);
}
+ void VisitDeclStmt(DeclStmt *DS) {
+ VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ OS << "static init " << VD->getName();
+ }
+
void VisitForStmt(ForStmt *F) {
OS << "for (" ;
if (F->getInit())