aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-05-01 23:10:44 +0000
committerJordan Rose <jordan_rose@apple.com>2013-05-01 23:10:44 +0000
commite2b1246a24e8babf2f58c93713fba16b8edb8e2d (patch)
treed8766203cedcf2cf15f3cdd862b207ebd89d374e /lib/StaticAnalyzer
parent776d3bb65c90278b9c65544b235d2ac40aea1d6e (diff)
[analyzer] Consolidate constant evaluation logic in SValBuilder.
Previously, this was scattered across Environment (literal expressions), ExprEngine (default arguments), and RegionStore (global constants). The former special-cased several kinds of simple constant expressions, while the latter two deferred to the AST's constant evaluator. Now, these are all unified as SValBuilder::getConstantVal(). To keep Environment fast, the special cases for simple constant expressions have been left in, but the main benefits are that (a) unusual constants like ObjCStringLiterals now work as default arguments and global constant initializers, and (b) we're not duplicating code between ExprEngine and RegionStore. This actually caught a bug in our test suite, which is awesome: we stop tracking allocated memory if it's passed as an argument along with some kind of callback, but not if the callback is 0. We were testing this in a case where the callback parameter had a default value, but that value was 0. After this change, the analyzer now (correctly) flags that as a leak! <rdar://problem/13773117> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180894 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp42
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp26
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp57
4 files changed, 72 insertions, 67 deletions
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index fe352aa8b4..7b133f6bf6 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -80,43 +80,17 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
llvm_unreachable("Should have been handled by ignoreTransparentExprs");
case Stmt::AddrLabelExprClass:
- return svalBuilder.makeLoc(cast<AddrLabelExpr>(S));
-
- case Stmt::CharacterLiteralClass: {
- const CharacterLiteral *C = cast<CharacterLiteral>(S);
- return svalBuilder.makeIntVal(C->getValue(), C->getType());
- }
-
+ case Stmt::CharacterLiteralClass:
case Stmt::CXXBoolLiteralExprClass:
- return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S));
-
case Stmt::CXXScalarValueInitExprClass:
- case Stmt::ImplicitValueInitExprClass: {
- QualType Ty = cast<Expr>(S)->getType();
- return svalBuilder.makeZeroVal(Ty);
- }
-
+ case Stmt::ImplicitValueInitExprClass:
case Stmt::IntegerLiteralClass:
- return svalBuilder.makeIntVal(cast<IntegerLiteral>(S));
-
case Stmt::ObjCBoolLiteralExprClass:
- return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S));
-
- // For special C0xx nullptr case, make a null pointer SVal.
case Stmt::CXXNullPtrLiteralExprClass:
- return svalBuilder.makeNull();
-
- case Stmt::ObjCStringLiteralClass: {
- MemRegionManager &MRMgr = svalBuilder.getRegionManager();
- const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S);
- return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL));
- }
-
- case Stmt::StringLiteralClass: {
- MemRegionManager &MRMgr = svalBuilder.getRegionManager();
- const StringLiteral *SL = cast<StringLiteral>(S);
- return svalBuilder.makeLoc(MRMgr.getStringRegion(SL));
- }
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::StringLiteralClass:
+ // Known constants; defer to SValBuilder.
+ return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
case Stmt::ReturnStmtClass: {
const ReturnStmt *RS = cast<ReturnStmt>(S);
@@ -127,10 +101,8 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
// Handle all other Stmt* using a lookup.
default:
- break;
+ return lookupExpr(EnvironmentEntry(S, LCtx));
}
-
- return lookupExpr(EnvironmentEntry(S, LCtx));
}
Environment EnvironmentManager::bindExpr(Environment Env,
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 5b6e97d3fb..0d5fb1785b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -741,20 +741,14 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S);
const Expr *ArgE = DefaultE->getExpr();
- // Avoid creating and destroying a lot of APSInts.
- SVal V;
- llvm::APSInt Result;
+ Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
+ if (!ConstantVal)
+ ConstantVal = UnknownVal();
for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
I != E; ++I) {
ProgramStateRef State = (*I)->getState();
-
- if (ArgE->EvaluateAsInt(Result, getContext()))
- V = svalBuilder.makeIntVal(Result);
- else
- V = State->getSVal(ArgE, LCtx);
-
- State = State->BindExpr(DefaultE, LCtx, V);
+ State = State->BindExpr(DefaultE, LCtx, *ConstantVal);
if (DefaultE->isGLValue())
State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
DefaultE);
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index dbfd9d6c99..3053e3610c 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1755,26 +1755,6 @@ SVal RegionStoreManager::getBindingForObjCIvar(RegionBindingsConstRef B,
return getBindingForLazySymbol(R);
}
-static Optional<SVal> getConstValue(SValBuilder &SVB, const VarDecl *VD) {
- ASTContext &Ctx = SVB.getContext();
- if (!VD->getType().isConstQualified())
- return None;
-
- const Expr *Init = VD->getInit();
- if (!Init)
- return None;
-
- llvm::APSInt Result;
- if (!Init->isGLValue() && Init->EvaluateAsInt(Result, Ctx))
- return SVB.makeIntVal(Result);
-
- if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
- return SVB.makeNull();
-
- // FIXME: Handle other possible constant expressions.
- return None;
-}
-
SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
const VarRegion *R) {
@@ -1791,8 +1771,10 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
return svalBuilder.getRegionValueSymbolVal(R);
// Is 'VD' declared constant? If so, retrieve the constant value.
- if (Optional<SVal> V = getConstValue(svalBuilder, VD))
- return *V;
+ if (VD->getType().isConstQualified())
+ if (const Expr *Init = VD->getInit())
+ if (Optional<SVal> V = svalBuilder.getConstantVal(Init))
+ return *V;
// This must come after the check for constants because closure-captured
// constant variables may appear in UnknownSpaceRegion.
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 5bab986ed0..652809777c 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -224,6 +224,63 @@ loc::MemRegionVal SValBuilder::getCXXThis(const CXXRecordDecl *D,
return loc::MemRegionVal(getRegionManager().getCXXThisRegion(PT, SFC));
}
+Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
+ E = E->IgnoreParens();
+
+ switch (E->getStmtClass()) {
+ // Handle expressions that we treat differently from the AST's constant
+ // evaluator.
+ case Stmt::AddrLabelExprClass:
+ return makeLoc(cast<AddrLabelExpr>(E));
+
+ case Stmt::CXXScalarValueInitExprClass:
+ case Stmt::ImplicitValueInitExprClass:
+ return makeZeroVal(E->getType());
+
+ case Stmt::ObjCStringLiteralClass: {
+ const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(E);
+ return makeLoc(getRegionManager().getObjCStringRegion(SL));
+ }
+
+ case Stmt::StringLiteralClass: {
+ const StringLiteral *SL = cast<StringLiteral>(E);
+ return makeLoc(getRegionManager().getStringRegion(SL));
+ }
+
+ // Fast-path some expressions to avoid the overhead of going through the AST's
+ // constant evaluator
+ case Stmt::CharacterLiteralClass: {
+ const CharacterLiteral *C = cast<CharacterLiteral>(E);
+ return makeIntVal(C->getValue(), C->getType());
+ }
+
+ case Stmt::CXXBoolLiteralExprClass:
+ return makeBoolVal(cast<CXXBoolLiteralExpr>(E));
+
+ case Stmt::IntegerLiteralClass:
+ return makeIntVal(cast<IntegerLiteral>(E));
+
+ case Stmt::ObjCBoolLiteralExprClass:
+ return makeBoolVal(cast<ObjCBoolLiteralExpr>(E));
+
+ case Stmt::CXXNullPtrLiteralExprClass:
+ return makeNull();
+
+ // If we don't have a special case, fall back to the AST's constant evaluator.
+ default: {
+ ASTContext &Ctx = getContext();
+ llvm::APSInt Result;
+ if (E->EvaluateAsInt(Result, Ctx))
+ return makeIntVal(Result);
+
+ if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+ return makeNull();
+
+ return None;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,