aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/ExprEngineC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngineC.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp270
1 files changed, 174 insertions, 96 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 93e598a27375..46cba81b14f7 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -50,7 +50,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
- SVal ExprVal = B->isLValue() ? LeftV : RightV;
+ SVal ExprVal = B->isGLValue() ? LeftV : RightV;
evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, LCtx, ExprVal),
LeftV, RightV);
continue;
@@ -58,6 +58,26 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
if (!B->isAssignmentOp()) {
StmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext);
+
+ if (B->isAdditiveOp()) {
+ // If one of the operands is a location, conjure a symbol for the other
+ // one (offset) if it's unknown so that memory arithmetic always
+ // results in an ElementRegion.
+ // TODO: This can be removed after we enable history tracking with
+ // SymSymExpr.
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
+ if (isa<Loc>(LeftV) &&
+ RHS->getType()->isIntegerType() && RightV.isUnknown()) {
+ RightV = svalBuilder.getConjuredSymbolVal(RHS, LCtx,
+ RHS->getType(), Count);
+ }
+ if (isa<Loc>(RightV) &&
+ LHS->getType()->isIntegerType() && LeftV.isUnknown()) {
+ LeftV = svalBuilder.getConjuredSymbolVal(LHS, LCtx,
+ LHS->getType(), Count);
+ }
+ }
+
// Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr).
SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
@@ -145,7 +165,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// In C++, assignment and compound assignment operators return an
// lvalue.
- if (B->isLValue())
+ if (B->isGLValue())
state = state->BindExpr(B, LCtx, location);
else
state = state->BindExpr(B, LCtx, Result);
@@ -162,14 +182,35 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
CanQualType T = getContext().getCanonicalType(BE->getType());
+
+ // Get the value of the block itself.
SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
Pred->getLocationContext());
+ ProgramStateRef State = Pred->getState();
+
+ // If we created a new MemRegion for the block, we should explicitly bind
+ // the captured variables.
+ if (const BlockDataRegion *BDR =
+ dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
+
+ BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(),
+ E = BDR->referenced_vars_end();
+
+ for (; I != E; ++I) {
+ const MemRegion *capturedR = I.getCapturedRegion();
+ const MemRegion *originalR = I.getOriginalRegion();
+ if (capturedR != originalR) {
+ SVal originalV = State->getSVal(loc::MemRegionVal(originalR));
+ State = State->bindLoc(loc::MemRegionVal(capturedR), originalV);
+ }
+ }
+ }
+
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
Bldr.generateNode(BE, Pred,
- Pred->getState()->BindExpr(BE, Pred->getLocationContext(),
- V),
+ State->BindExpr(BE, Pred->getLocationContext(), V),
false, 0,
ProgramPoint::PostLValueKind);
@@ -238,7 +279,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
- case CK_LValueBitCast:
case CK_IntegralCast:
case CK_NullToPointer:
case CK_IntegralToPointer:
@@ -278,7 +318,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
SVal val = state->getSVal(Ex, LCtx);
- val = getStoreManager().evalDerivedToBase(val, T);
+ val = getStoreManager().evalDerivedToBase(val, CastE);
state = state->BindExpr(CastE, LCtx, val);
Bldr.generateNode(CastE, Pred, state);
continue;
@@ -291,7 +331,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// Compute the type of the result.
QualType resultType = CastE->getType();
- if (CastE->isLValue())
+ if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);
bool Failed = false;
@@ -337,10 +377,11 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
case CK_VectorSplat:
- case CK_MemberPointerToBoolean: {
+ case CK_MemberPointerToBoolean:
+ case CK_LValueBitCast: {
// Recover some path-sensitivty by conjuring a new value.
QualType resultType = CastE->getType();
- if (CastE->isLValue())
+ if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);
const LocationContext *LCtx = Pred->getLocationContext();
SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, LCtx,
@@ -366,8 +407,16 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
SVal ILV = state->getSVal(ILE, Pred->getLocationContext());
const LocationContext *LC = Pred->getLocationContext();
state = state->bindCompoundLiteral(CL, LC, ILV);
-
- if (CL->isLValue())
+
+ // Compound literal expressions are a GNU extension in C++.
+ // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues,
+ // and like temporary objects created by the functional notation T()
+ // CLs are destroyed at the end of the containing full-expression.
+ // HOWEVER, an rvalue of array type is not something the analyzer can
+ // reason about, since we expect all regions to be wrapped in Locs.
+ // So we treat array CLs as lvalues as well, knowing that they will decay
+ // to pointers as soon as they are used.
+ if (CL->isGLValue() || CL->getType()->isArrayType())
B.generateNode(CL, Pred, state->BindExpr(CL, LC, state->getLValue(CL, LC)));
else
B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV));
@@ -404,31 +453,39 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
const LocationContext *LC = N->getLocationContext();
if (const Expr *InitEx = VD->getInit()) {
- SVal InitVal = state->getSVal(InitEx, Pred->getLocationContext());
-
- // We bound the temp obj region to the CXXConstructExpr. Now recover
- // the lazy compound value when the variable is not a reference.
- if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
- !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
- InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
- assert(isa<nonloc::LazyCompoundVal>(InitVal));
- }
-
- // Recover some path-sensitivity if a scalar value evaluated to
- // UnknownVal.
- if (InitVal.isUnknown()) {
- QualType Ty = InitEx->getType();
- if (InitEx->isLValue()) {
- Ty = getContext().getPointerType(Ty);
- }
-
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
- currentBuilderContext->getCurrentBlockCount());
+ SVal InitVal = state->getSVal(InitEx, LC);
+
+ if (InitVal == state->getLValue(VD, LC) ||
+ (VD->getType()->isArrayType() &&
+ isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) {
+ // We constructed the object directly in the variable.
+ // No need to bind anything.
+ B.generateNode(DS, N, state);
+ } else {
+ // We bound the temp obj region to the CXXConstructExpr. Now recover
+ // the lazy compound value when the variable is not a reference.
+ if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
+ !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
+ InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
+ assert(isa<nonloc::LazyCompoundVal>(InitVal));
+ }
+
+ // Recover some path-sensitivity if a scalar value evaluated to
+ // UnknownVal.
+ if (InitVal.isUnknown()) {
+ QualType Ty = InitEx->getType();
+ if (InitEx->isGLValue()) {
+ Ty = getContext().getPointerType(Ty);
+ }
+
+ InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
+ currentBuilderContext->getCurrentBlockCount());
+ }
+ B.takeNodes(N);
+ ExplodedNodeSet Dst2;
+ evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
+ B.addNodes(Dst2);
}
- B.takeNodes(N);
- ExplodedNodeSet Dst2;
- evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
- B.addNodes(Dst2);
}
else {
B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC)));
@@ -443,48 +500,44 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- SVal X = state->getSVal(B, LCtx);
- assert(X.isUndef());
-
- const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
- assert(Ex);
-
- if (Ex == B->getRHS()) {
- X = state->getSVal(Ex, LCtx);
-
- // Handle undefined values.
- if (X.isUndef()) {
- Bldr.generateNode(B, Pred, state->BindExpr(B, LCtx, X));
- return;
- }
-
- DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
-
- // We took the RHS. Because the value of the '&&' or '||' expression must
- // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
- // or 1. Alternatively, we could take a lazy approach, and calculate this
- // value later when necessary. We don't have the machinery in place for
- // this right now, and since most logical expressions are used for branches,
- // the payoff is not likely to be large. Instead, we do eager evaluation.
- if (ProgramStateRef newState = state->assume(XD, true))
- Bldr.generateNode(B, Pred,
- newState->BindExpr(B, LCtx,
- svalBuilder.makeIntVal(1U, B->getType())));
-
- if (ProgramStateRef newState = state->assume(XD, false))
- Bldr.generateNode(B, Pred,
- newState->BindExpr(B, LCtx,
- svalBuilder.makeIntVal(0U, B->getType())));
+
+ ExplodedNode *N = Pred;
+ while (!isa<BlockEntrance>(N->getLocation())) {
+ ProgramPoint P = N->getLocation();
+ assert(isa<PreStmt>(P)|| isa<PreStmtPurgeDeadSymbols>(P));
+ (void) P;
+ assert(N->pred_size() == 1);
+ N = *N->pred_begin();
+ }
+ assert(N->pred_size() == 1);
+ N = *N->pred_begin();
+ BlockEdge BE = cast<BlockEdge>(N->getLocation());
+ SVal X;
+
+ // Determine the value of the expression by introspecting how we
+ // got this location in the CFG. This requires looking at the previous
+ // block we were in and what kind of control-flow transfer was involved.
+ const CFGBlock *SrcBlock = BE.getSrc();
+ // The only terminator (if there is one) that makes sense is a logical op.
+ CFGTerminator T = SrcBlock->getTerminator();
+ if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(T.getStmt())) {
+ (void) Term;
+ assert(Term->isLogicalOp());
+ assert(SrcBlock->succ_size() == 2);
+ // Did we take the true or false branch?
+ unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0;
+ X = svalBuilder.makeIntVal(constant, B->getType());
}
else {
- // We took the LHS expression. Depending on whether we are '&&' or
- // '||' we know what the value of the expression is via properties of
- // the short-circuiting.
- X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U,
- B->getType());
- Bldr.generateNode(B, Pred, state->BindExpr(B, LCtx, X));
+ // If there is no terminator, by construction the last statement
+ // in SrcBlock is the value of the enclosing expression.
+ assert(!SrcBlock->empty());
+ CFGStmt Elem = cast<CFGStmt>(*SrcBlock->rbegin());
+ const Stmt *S = Elem.getStmt();
+ X = N->getState()->getSVal(S, Pred->getLocationContext());
}
+
+ Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X));
}
void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
@@ -519,16 +572,17 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
svalBuilder.makeCompoundVal(T, vals)));
return;
}
-
- if (Loc::isLocType(T) || T->isIntegerType()) {
- assert(IE->getNumInits() == 1);
- const Expr *initEx = IE->getInit(0);
- B.generateNode(IE, Pred, state->BindExpr(IE, LCtx,
- state->getSVal(initEx, LCtx)));
- return;
- }
-
- llvm_unreachable("unprocessed InitListExpr type");
+
+ // Handle scalars: int{5} and int{}.
+ assert(NumInitElements <= 1);
+
+ SVal V;
+ if (NumInitElements == 0)
+ V = getSValBuilder().makeZeroVal(T);
+ else
+ V = state->getSVal(IE->getInit(0), LCtx);
+
+ B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
}
void ExprEngine::VisitGuardedExpr(const Expr *Ex,
@@ -537,17 +591,41 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
-
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
- SVal X = state->getSVal(Ex, LCtx);
- assert (X.isUndef());
- const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
- assert(SE);
- X = state->getSVal(SE, LCtx);
-
- // Make sure that we invalidate the previous binding.
- B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, X, true));
+ const CFGBlock *SrcBlock = 0;
+
+ for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) {
+ ProgramPoint PP = N->getLocation();
+ if (isa<PreStmtPurgeDeadSymbols>(PP) || isa<BlockEntrance>(PP)) {
+ assert(N->pred_size() == 1);
+ continue;
+ }
+ SrcBlock = cast<BlockEdge>(&PP)->getSrc();
+ break;
+ }
+
+ // Find the last expression in the predecessor block. That is the
+ // expression that is used for the value of the ternary expression.
+ bool hasValue = false;
+ SVal V;
+
+ for (CFGBlock::const_reverse_iterator I = SrcBlock->rbegin(),
+ E = SrcBlock->rend(); I != E; ++I) {
+ CFGElement CE = *I;
+ if (CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+ const Expr *ValEx = cast<Expr>(CS->getStmt());
+ hasValue = true;
+ V = state->getSVal(ValEx, LCtx);
+ break;
+ }
+ }
+
+ assert(hasValue);
+ (void) hasValue;
+
+ // Generate a new node with the binding from the appropriate path.
+ B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true));
}
void ExprEngine::
@@ -648,7 +726,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
}
case UO_Plus:
- assert(!U->isLValue());
+ assert(!U->isGLValue());
// FALL-THROUGH.
case UO_Deref:
case UO_AddrOf:
@@ -671,7 +749,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
case UO_LNot:
case UO_Minus:
case UO_Not: {
- assert (!U->isLValue());
+ assert (!U->isGLValue());
const Expr *Ex = U->getSubExpr()->IgnoreParens();
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
@@ -796,7 +874,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
// Since the lvalue-to-rvalue conversion is explicit in the AST,
// we bind an l-value if the operator is prefix and an lvalue (in C++).
- if (U->isLValue())
+ if (U->isGLValue())
state = state->BindExpr(U, LCtx, loc);
else
state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result);