summaryrefslogtreecommitdiffstats
path: root/lib/StaticAnalyzer/Core/SValBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core/SValBuilder.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp105
1 files changed, 95 insertions, 10 deletions
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index c72e780..9d77a3e 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -33,7 +33,7 @@ DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) {
if (Loc::isLocType(type))
return makeNull();
- if (type->isIntegerType())
+ if (type->isIntegralOrEnumerationType())
return makeIntVal(0, type);
// FIXME: Handle floats.
@@ -106,12 +106,19 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
- const Expr *expr,
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag,
+ const Expr *Ex,
const LocationContext *LCtx,
- unsigned count) {
- QualType T = expr->getType();
- return conjureSymbolVal(symbolTag, expr, LCtx, T, count);
+ unsigned Count) {
+ QualType T = Ex->getType();
+
+ // Compute the type of the result. If the expression is not an R-value, the
+ // result should be a location.
+ QualType ExType = Ex->getType();
+ if (Ex->isGLValue())
+ T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType);
+
+ return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count);
}
DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
@@ -217,6 +224,68 @@ 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: {
+ // Don't try to come up with a value for materialized temporaries.
+ if (E->isGLValue())
+ return None;
+
+ ASTContext &Ctx = getContext();
+ llvm::APSInt Result;
+ if (E->EvaluateAsInt(Result, Ctx))
+ return makeIntVal(Result);
+
+ if (Loc::isLocType(E->getType()))
+ if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+ return makeNull();
+
+ return None;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,
@@ -320,6 +389,22 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
if (val.isUnknownOrUndef() || castTy == originalTy)
return val;
+ if (castTy->isBooleanType()) {
+ if (val.isUnknownOrUndef())
+ return val;
+ if (val.isConstant())
+ return makeTruthVal(!val.isZeroConstant(), castTy);
+ if (SymbolRef Sym = val.getAsSymbol()) {
+ BasicValueFactory &BVF = getBasicValueFactory();
+ // FIXME: If we had a state here, we could see if the symbol is known to
+ // be zero, but we don't.
+ return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy);
+ }
+
+ assert(val.getAs<Loc>());
+ return makeTruthVal(true, castTy);
+ }
+
// For const casts, casts to void, just propagate the value.
if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy),
@@ -327,11 +412,11 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
return val;
// Check for casts from pointers to integers.
- if (castTy->isIntegerType() && Loc::isLocType(originalTy))
+ if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy))
return evalCastFromLoc(val.castAs<Loc>(), castTy);
// Check for casts from integers to pointers.
- if (Loc::isLocType(castTy) && originalTy->isIntegerType()) {
+ if (Loc::isLocType(castTy) && originalTy->isIntegralOrEnumerationType()) {
if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) {
if (const MemRegion *R = LV->getLoc().getAsRegion()) {
StoreManager &storeMgr = StateMgr.getStoreManager();
@@ -361,7 +446,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// Are we casting from an array to an integer? If so, cast the decayed
// pointer value to an integer.
- assert(castTy->isIntegerType());
+ assert(castTy->isIntegralOrEnumerationType());
// FIXME: Keep these here for now in case we decide soon that we
// need the original decayed type.
@@ -373,7 +458,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// Check for casts from a region to a specific type.
if (const MemRegion *R = val.getAsRegion()) {
// Handle other casts of locations to integers.
- if (castTy->isIntegerType())
+ if (castTy->isIntegralOrEnumerationType())
return evalCastFromLoc(loc::MemRegionVal(R), castTy);
// FIXME: We should handle the case where we strip off view layers to get
OpenPOWER on IntegriCloud