r174676 - [analyzer] Don't reinitialize static globals more than once along a path
Anna Zaks
ganna at apple.com
Thu Feb 7 15:05:37 PST 2013
Author: zaks
Date: Thu Feb 7 17:05:37 2013
New Revision: 174676
URL: http://llvm.org/viewvc/llvm-project?rev=174676&view=rev
Log:
[analyzer] Don't reinitialize static globals more than once along a path
This patch makes sure that we do not reinitialize static globals when
the function is called more than once along a path. The motivation is
code with initialization patterns that rely on 2 static variables, where
one of them has an initializer while the other does not. Currently, we
reset the static variables with initializers on every visit to the
function along a path.
Added:
cfe/trunk/test/Analysis/global_region_invalidation.mm
Modified:
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp
cfe/trunk/test/Analysis/global-region-invalidation.c
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp?rev=174676&r1=174675&r2=174676&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp Thu Feb 7 17:05:37 2013
@@ -423,37 +423,53 @@ void ExprEngine::VisitCompoundLiteralExp
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) {
-
- // FIXME: static variables may have an initializer, but the second
- // time a function is called those values may not be current.
- // This may need to be reflected in the CFG.
-
// Assumption: The CFG has one DeclStmt per Decl.
const Decl *D = *DS->decl_begin();
-
- if (!D || !isa<VarDecl>(D)) {
+ const VarDecl *VD = dyn_cast_or_null<VarDecl>(D);
+
+ if (!D || !VD) {
//TODO:AZ: remove explicit insertion after refactoring is done.
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;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
- const VarDecl *VD = dyn_cast<VarDecl>(D);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
ExplodedNode *N = *I;
ProgramStateRef state = N->getState();
-
- // Decls without InitExpr are not initialized explicitly.
const LocationContext *LC = N->getLocationContext();
-
+
+ // Decls without InitExpr are not initialized explicitly.
if (const Expr *InitEx = VD->getInit()) {
+
+ // 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 (InitVal == state->getLValue(VD, LC) ||
@@ -461,7 +477,7 @@ void ExprEngine::VisitDeclStmt(const Dec
isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) {
// We constructed the object directly in the variable.
// No need to bind anything.
- B.generateNode(DS, N, state);
+ B.generateNode(DS, UpdatedN, state);
} else {
// We bound the temp obj region to the CXXConstructExpr. Now recover
// the lazy compound value when the variable is not a reference.
@@ -482,9 +498,11 @@ void ExprEngine::VisitDeclStmt(const Dec
InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty,
currBldrCtx->blockCount());
}
- B.takeNodes(N);
+
+
+ B.takeNodes(UpdatedN);
ExplodedNodeSet Dst2;
- evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
+ evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, LC), InitVal, true);
B.addNodes(Dst2);
}
}
Modified: cfe/trunk/test/Analysis/global-region-invalidation.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/global-region-invalidation.c?rev=174676&r1=174675&r2=174676&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/global-region-invalidation.c (original)
+++ cfe/trunk/test/Analysis/global-region-invalidation.c Thu Feb 7 17:05:37 2013
@@ -84,3 +84,27 @@ void testAnalyzerEvalIsPure() {
}
}
+// Test that static variables with initializers do not get reinitialized on
+// recursive calls.
+void Function2(void);
+int *getPtr();
+void Function1(void) {
+ static unsigned flag;
+ static int *p = 0;
+ if (!flag) {
+ flag = 1;
+ p = getPtr();
+ }
+ int m = *p; // no-warning: p is never null.
+ m++;
+ Function2();
+}
+void Function2(void) {
+ Function1();
+}
+
+void SetToNonZero(void) {
+ static int g = 5;
+ clang_analyzer_eval(g == 5); // expected-warning{{TRUE}}
+}
+
Added: cfe/trunk/test/Analysis/global_region_invalidation.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/global_region_invalidation.mm?rev=174676&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/global_region_invalidation.mm (added)
+++ cfe/trunk/test/Analysis/global_region_invalidation.mm Thu Feb 7 17:05:37 2013
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+void use(int);
+id foo(int x) {
+ if (x)
+ return 0;
+ static id p = foo(1);
+ clang_analyzer_eval(p == 0); // expected-warning{{TRUE}}
+ return p;
+}
\ No newline at end of file
More information about the cfe-commits
mailing list