Newer
Older
// Check for loads/stores from/to unknown locations. Treat as No-Ops.
if (location.isUnknown())
return St;
// During a load, one of two possible situations arise:
// (1) A crash, because the location (pointer) was NULL.
// (2) The location (pointer) is not NULL, and the dereference works.
//
// We add these assumptions.
Zhongxing Xu
committed
Loc LV = cast<Loc>(location);
// "Assume" that the pointer is not NULL.
bool isFeasibleNotNull = false;
const GRState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
// "Assume" that the pointer is NULL.
bool isFeasibleNull = false;
Ted Kremenek
committed
GRStateRef StNull = GRStateRef(Assume(St, LV, false, isFeasibleNull),
getStateManager());
if (isFeasibleNull) {
Ted Kremenek
committed
// Use the Generic Data Map to mark in the state what lval was null.
Zhongxing Xu
committed
const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV);
Ted Kremenek
committed
StNull = StNull.set<GRState::NullDerefTag>(PersistentLV);
// We don't use "MakeNode" here because the node will be a sink
// and we have no intention of processing it later.
ProgramPoint::Kind K =
isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind;
NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred, K);
if (NullNode) {
NullNode->markAsSink();
if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
else ExplicitNullDeref.insert(NullNode);
}
}
return isFeasibleNotNull ? StNotNull : NULL;
//===----------------------------------------------------------------------===//
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
NodeSet& Dst) {
// Process the arguments.
if (AI != AE) {
NodeSet DstTmp;
Visit(*AI, Pred, DstTmp);
++AI;
for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI)
VisitCall(CE, *DI, AI, AE, Dst);
return;
}
// If we reach here we have processed all of the arguments. Evaluate
// the callee expression.
NodeSet DstTmp;
Expr* Callee = CE->getCallee()->IgnoreParens();
Zhongxing Xu
committed
Visit(Callee, Pred, DstTmp);
// Finally, evaluate the function call.
for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) {
Zhongxing Xu
committed
SVal L = GetSVal(St, Callee);
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
// Check for undefined control-flow or calls to NULL.
Zhongxing Xu
committed
if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
NodeTy* N = Builder->generateNode(CE, St, *DI);
if (N) {
N->markAsSink();
BadCalls.insert(N);
}
Ted Kremenek
committed
}
// Check for the "noreturn" attribute.
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Zhongxing Xu
committed
if (isa<loc::FuncVal>(L)) {
Zhongxing Xu
committed
FunctionDecl* FD = cast<loc::FuncVal>(L).getDecl();
if (FD->getAttr<NoReturnAttr>())
Ted Kremenek
committed
Builder->BuildSinks = true;
else {
// HACK: Some functions are not marked noreturn, and don't return.
// Here are a few hardwired ones. If this takes too long, we can
// potentially cache these results.
const char* s = FD->getIdentifier()->getName();
unsigned n = strlen(s);
switch (n) {
default:
break;
case 4:
if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true;
break;
case 5:
if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true;
else if (!memcmp(s, "error", 5)) {
if (CE->getNumArgs() > 0) {
Zhongxing Xu
committed
SVal X = GetSVal(St, *CE->arg_begin());
// FIXME: use Assume to inspect the possible symbolic value of
// X. Also check the specific signature of error().
Zhongxing Xu
committed
nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&X);
if (CI && CI->getValue() != 0)
Builder->BuildSinks = true;
if (!memcmp(s, "Assert", 6)) {
Builder->BuildSinks = true;
break;
}
// FIXME: This is just a wrapper around throwing an exception.
// Eventually inter-procedural analysis should handle this easily.
if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true;
break;
case 7:
if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true;
case 8:
if (!memcmp(s ,"db_error", 8)) Builder->BuildSinks = true;
break;
case 12:
if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true;
break;
case 13:
if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true;
break;
case 14:
if (!memcmp(s, "dtrace_assfail", 14)) Builder->BuildSinks = true;
break;
if (!memcmp(s, "_XCAssertionFailureHandler", 26) ||
!memcmp(s, "_DTAssertionFailureHandler", 26))
}
}
}
Ted Kremenek
committed
// Evaluate the call.
Zhongxing Xu
committed
if (isa<loc::FuncVal>(L)) {
Zhongxing Xu
committed
IdentifierInfo* Info = cast<loc::FuncVal>(L).getDecl()->getIdentifier();
switch (id) {
case Builtin::BI__builtin_expect: {
// For __builtin_expect, just return the value of the subexpression.
assert (CE->arg_begin() != CE->arg_end());
Zhongxing Xu
committed
SVal X = GetSVal(St, *(CE->arg_begin()));
MakeNode(Dst, CE, *DI, SetSVal(St, CE, X));
continue;
}
default:
break;
}
}
// Check any arguments passed-by-value against being undefined.
bool badArg = false;
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
Zhongxing Xu
committed
if (GetSVal(GetState(*DI), *I).isUndef()) {
NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI);
if (N) {
N->markAsSink();
UndefArgs[N] = *I;
}
if (badArg)
continue;
// Dispatch to the plug-in transfer function.
unsigned size = Dst.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
EvalCall(Dst, CE, L, *DI);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && Dst.size() == size &&
!Builder->HasGeneratedNode)
MakeNode(Dst, CE, *DI, St);
}
}
//===----------------------------------------------------------------------===//
// Transfer function: Objective-C ivar references.
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex,
NodeTy* Pred, NodeSet& Dst,
bool asLValue) {
Expr* Base = cast<Expr>(Ex->getBase());
NodeSet Tmp;
Visit(Base, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const GRState* St = GetState(*I);
Zhongxing Xu
committed
SVal BaseVal = GetSVal(St, Base);
SVal location = StateMgr.GetLValue(St, Ex->getDecl(), BaseVal);
Zhongxing Xu
committed
MakeNode(Dst, Ex, *I, SetSVal(St, Ex, location));
else
EvalLoad(Dst, Ex, *I, St, location);
}
}
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
//===----------------------------------------------------------------------===//
// Transfer function: Objective-C message expressions.
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred,
NodeSet& Dst){
VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
Pred, Dst);
}
void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
ObjCMessageExpr::arg_iterator AI,
ObjCMessageExpr::arg_iterator AE,
NodeTy* Pred, NodeSet& Dst) {
if (AI == AE) {
// Process the receiver.
if (Expr* Receiver = ME->getReceiver()) {
NodeSet Tmp;
Visit(Receiver, Pred, Tmp);
for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
VisitObjCMessageExprDispatchHelper(ME, *NI, Dst);
return;
}
VisitObjCMessageExprDispatchHelper(ME, Pred, Dst);
return;
}
NodeSet Tmp;
Visit(*AI, Pred, Tmp);
++AI;
for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst);
}
void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
NodeTy* Pred,
NodeSet& Dst) {
// FIXME: More logic for the processing the method call.
Ted Kremenek
committed
bool RaisesException = false;
if (Expr* Receiver = ME->getReceiver()) {
Zhongxing Xu
committed
SVal L = GetSVal(St, Receiver);
// Check for undefined control-flow or calls to NULL.
if (L.isUndef()) {
NodeTy* N = Builder->generateNode(ME, St, Pred);
if (N) {
N->markAsSink();
UndefReceivers.insert(N);
}
return;
}
Ted Kremenek
committed
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
// Check if the "raise" message was sent.
if (ME->getSelector() == RaiseSel)
RaisesException = true;
}
else {
IdentifierInfo* ClsName = ME->getClassName();
Selector S = ME->getSelector();
// Check for special instance methods.
if (!NSExceptionII) {
ASTContext& Ctx = getContext();
NSExceptionII = &Ctx.Idents.get("NSException");
}
if (ClsName == NSExceptionII) {
enum { NUM_RAISE_SELECTORS = 2 };
// Lazily create a cache of the selectors.
if (!NSExceptionInstanceRaiseSelectors) {
ASTContext& Ctx = getContext();
NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
unsigned idx = 0;
// raise:format:
II.push_back(&Ctx.Idents.get("raise"));
II.push_back(&Ctx.Idents.get("format"));
Ted Kremenek
committed
NSExceptionInstanceRaiseSelectors[idx++] =
Ctx.Selectors.getSelector(II.size(), &II[0]);
// raise:format::arguments:
II.push_back(&Ctx.Idents.get("arguments"));
Ted Kremenek
committed
NSExceptionInstanceRaiseSelectors[idx++] =
Ctx.Selectors.getSelector(II.size(), &II[0]);
}
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
if (S == NSExceptionInstanceRaiseSelectors[i]) {
RaisesException = true; break;
}
}
}
// Check for any arguments that are uninitialized/undefined.
for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
I != E; ++I) {
Zhongxing Xu
committed
if (GetSVal(St, *I).isUndef()) {
// Generate an error node for passing an uninitialized/undefined value
// as an argument to a message expression. This node is a sink.
NodeTy* N = Builder->generateNode(ME, St, Pred);
if (N) {
N->markAsSink();
MsgExprUndefArgs[N] = *I;
}
return;
}
Ted Kremenek
committed
}
// Check if we raise an exception. For now treat these as sinks. Eventually
// we will want to handle exceptions properly.
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
if (RaisesException)
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
unsigned size = Dst.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
EvalObjCMessageExpr(Dst, ME, Pred);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
MakeNode(Dst, ME, Pred, St);
//===----------------------------------------------------------------------===//
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
NodeSet S1;
QualType T = CastE->getType();
QualType ExTy = Ex->getType();
if (ExTy->isArrayType() || T->isReferenceType())
Zhongxing Xu
committed
VisitLValue(Ex, Pred, S1);
else
Visit(Ex, Pred, S1);
Ted Kremenek
committed
// Check for casting to "void".
if (T->isVoidType()) {
for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1)
Dst.Add(*I1);
return;
}
Ted Kremenek
committed
// FIXME: The rest of this should probably just go into EvalCall, and
// let the transfer function object be responsible for constructing
// nodes.
for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
NodeTy* N = *I1;
Zhongxing Xu
committed
SVal V = GetSVal(St, Ex);
Ted Kremenek
committed
// Unknown?
if (V.isUnknown()) {
Dst.Add(N);
continue;
}
// Undefined?
if (V.isUndef()) {
Zhongxing Xu
committed
MakeNode(Dst, CastE, N, SetSVal(St, CastE, V));
Ted Kremenek
committed
continue;
}
Ted Kremenek
committed
// For const casts, just propagate the value.
ASTContext& C = getContext();
if (C.getCanonicalType(T).getUnqualifiedType() ==
C.getCanonicalType(ExTy).getUnqualifiedType()) {
Zhongxing Xu
committed
MakeNode(Dst, CastE, N, SetSVal(St, CastE, V));
Ted Kremenek
committed
continue;
}
Ted Kremenek
committed
// Check for casts from pointers to integers.
Zhongxing Xu
committed
if (T->isIntegerType() && Loc::IsLocType(ExTy)) {
Ted Kremenek
committed
unsigned bits = getContext().getTypeSize(ExTy);
// FIXME: Determine if the number of bits of the target type is
// equal or exceeds the number of bits to store the pointer value.
// If not, flag an error.
Zhongxing Xu
committed
V = nonloc::LocAsInteger::Make(getBasicVals(), cast<Loc>(V), bits);
MakeNode(Dst, CastE, N, SetSVal(St, CastE, V));
Ted Kremenek
committed
continue;
}
// Check for casts from integers to pointers.
Zhongxing Xu
committed
if (Loc::IsLocType(T) && ExTy->isIntegerType())
if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&V)) {
Ted Kremenek
committed
// Just unpackage the lval and return it.
Zhongxing Xu
committed
V = LV->getLoc();
MakeNode(Dst, CastE, N, SetSVal(St, CastE, V));
Ted Kremenek
committed
continue;
}
// All other cases.
Zhongxing Xu
committed
MakeNode(Dst, CastE, N, SetSVal(St, CastE, EvalCast(V, CastE->getType())));
void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
Ted Kremenek
committed
// The CFG has one DeclStmt per Decl.
ScopedDecl* D = *DS->decl_begin();
return;
const VarDecl* VD = dyn_cast<VarDecl>(D);
// FIXME: Add support for local arrays.
if (VD->getType()->isArrayType()) {
return;
}
Expr* Ex = const_cast<Expr*>(VD->getInit());
// FIXME: static variables may have an initializer, but the second
// time a function is called those values may not be current.
NodeSet Tmp;
if (Ex)
Visit(Ex, Pred, Tmp);
if (Tmp.empty())
Tmp.Add(Pred);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
St = StateMgr.AddDecl(St, VD, Ex, Builder->getCurrentBlockCount());
}
}
/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex,
NodeTy* Pred,
NodeSet& Dst) {
QualType T = Ex->getArgumentType();
uint64_t amt;
if (Ex->isSizeOf()) {
// FIXME: Add support for VLAs.
if (!T.getTypePtr()->isConstantSizeType())
return;
Ted Kremenek
committed
// Some code tries to take the sizeof an ObjCInterfaceType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
if (T->isObjCInterfaceType())
return;
amt = 1; // Handle sizeof(void)
if (T != getContext().VoidTy)
amt = getContext().getTypeSize(T) / 8;
}
else // Get alignment of the type.
amt = getContext().getTypeAlign(T) / 8;
Zhongxing Xu
committed
SetSVal(GetState(Pred), Ex,
NonLoc::MakeVal(getBasicVals(), amt, Ex->getType())));
Ted Kremenek
committed
}
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
Zhongxing Xu
committed
NodeSet& Dst, bool asLValue) {
switch (U->getOpcode()) {
default:
break;
Ted Kremenek
committed
case UnaryOperator::Deref: {
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
SVal location = GetSVal(St, Ex);
Zhongxing Xu
committed
if (asLValue)
Zhongxing Xu
committed
MakeNode(Dst, U, *I, SetSVal(St, U, location));
Ted Kremenek
committed
EvalLoad(Dst, U, *I, St, location);
}
Ted Kremenek
committed
case UnaryOperator::Real: {
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
// FIXME: We don't have complex SValues yet.
Ted Kremenek
committed
if (Ex->getType()->isAnyComplexType()) {
// Just report "Unknown."
Dst.Add(*I);
continue;
}
// For all other types, UnaryOperator::Real is an identity operation.
assert (U->getType() == Ex->getType());
Zhongxing Xu
committed
MakeNode(Dst, U, *I, SetSVal(St, U, GetSVal(St, Ex)));
Ted Kremenek
committed
}
return;
}
case UnaryOperator::Imag: {
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
// FIXME: We don't have complex SValues yet.
Ted Kremenek
committed
if (Ex->getType()->isAnyComplexType()) {
// Just report "Unknown."
Dst.Add(*I);
continue;
}
// For all other types, UnaryOperator::Float returns 0.
assert (Ex->getType()->isIntegerType());
Zhongxing Xu
committed
SVal X = NonLoc::MakeVal(getBasicVals(), 0, Ex->getType());
MakeNode(Dst, U, *I, SetSVal(St, U, X));
Ted Kremenek
committed
}
return;
}
// FIXME: Just report "Unknown" for OffsetOf.
case UnaryOperator::OffsetOf:
Dst.Add(Pred);
return;
Zhongxing Xu
committed
case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH.
case UnaryOperator::Extension: {
// Unary "+" is a no-op, similar to a parentheses. We still have places
// where it may be a block-level expression, so we need to
// generate an extra node that just propagates the value of the
// subexpression.
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
MakeNode(Dst, U, *I, SetSVal(St, U, GetSVal(St, Ex)));
return;
}
case UnaryOperator::AddrOf: {
Zhongxing Xu
committed
assert(!asLValue);
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Zhongxing Xu
committed
VisitLValue(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
SVal V = GetSVal(St, Ex);
St = SetSVal(St, U, V);
MakeNode(Dst, U, *I, St);
}
return;
}
case UnaryOperator::LNot:
case UnaryOperator::Minus:
case UnaryOperator::Not: {
Zhongxing Xu
committed
assert (!asLValue);
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Ted Kremenek
committed
// Get the value of the subexpression.
Zhongxing Xu
committed
SVal V = GetSVal(St, Ex);
Ted Kremenek
committed
// Perform promotions.
// FIXME: This is the right thing to do, but it currently breaks
// a bunch of tests.
// V = EvalCast(V, U->getType());
if (V.isUnknownOrUndef()) {
Zhongxing Xu
committed
MakeNode(Dst, U, *I, SetSVal(St, U, V));
continue;
}
switch (U->getOpcode()) {
default:
assert(false && "Invalid Opcode.");
break;
case UnaryOperator::Not:
Ted Kremenek
committed
// FIXME: Do we need to handle promotions?
Zhongxing Xu
committed
St = SetSVal(St, U, EvalComplement(cast<NonLoc>(V)));
break;
case UnaryOperator::Minus:
Ted Kremenek
committed
// FIXME: Do we need to handle promotions?
Zhongxing Xu
committed
St = SetSVal(St, U, EvalMinus(U, cast<NonLoc>(V)));
break;
case UnaryOperator::LNot:
// C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
//
// Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E".
Zhongxing Xu
committed
if (isa<Loc>(V)) {
loc::ConcreteInt X(getBasicVals().getZeroWithPtrWidth());
SVal Result = EvalBinOp(BinaryOperator::EQ, cast<Loc>(V), X);
St = SetSVal(St, U, Result);
}
else {
Zhongxing Xu
committed
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
Ted Kremenek
committed
#if 0
Zhongxing Xu
committed
SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X);
St = SetSVal(St, U, Result);
Ted Kremenek
committed
#else
Zhongxing Xu
committed
EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I);
Ted Kremenek
committed
continue;
#endif
}
break;
}
MakeNode(Dst, U, *I, St);
}
return;
}
Ted Kremenek
committed
case UnaryOperator::AlignOf: {
QualType T = U->getSubExpr()->getType();
// FIXME: Add support for VLAs.
if (!T.getTypePtr()->isConstantSizeType())
return;
uint64_t size = getContext().getTypeAlign(T) / 8;
const GRState* St = GetState(Pred);
St = SetSVal(St, U, NonLoc::MakeVal(getBasicVals(), size, U->getType()));
MakeNode(Dst, U, Pred, St);
return;
}
case UnaryOperator::SizeOf: {
QualType T = U->getSubExpr()->getType();
// FIXME: Add support for VLAs.
if (!T.getTypePtr()->isConstantSizeType())
return;
uint64_t size = getContext().getTypeSize(T) / 8;
Zhongxing Xu
committed
St = SetSVal(St, U, NonLoc::MakeVal(getBasicVals(), size, U->getType()));
MakeNode(Dst, U, Pred, St);
return;
}
}
Ted Kremenek
committed
// Handle ++ and -- (both pre- and post-increment).
Ted Kremenek
committed
assert (U->isIncrementDecrementOp());
NodeSet Tmp;
Expr* Ex = U->getSubExpr()->IgnoreParens();
Zhongxing Xu
committed
VisitLValue(Ex, Pred, Tmp);
for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
SVal V1 = GetSVal(St, Ex);
// Perform a load.
NodeSet Tmp2;
EvalLoad(Tmp2, Ex, *I, St, V1);
for (NodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) {
St = GetState(*I2);
Zhongxing Xu
committed
SVal V2 = GetSVal(St, Ex);
// Propagate unknown and undefined values.
if (V2.isUnknownOrUndef()) {
Zhongxing Xu
committed
MakeNode(Dst, U, *I2, SetSVal(St, U, V2));
continue;
}
Ted Kremenek
committed
// Handle all other values.
Ted Kremenek
committed
BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
: BinaryOperator::Sub;
Ted Kremenek
committed
Zhongxing Xu
committed
SVal Result = EvalBinOp(Op, V2, MakeConstantVal(1U, U));
St = SetSVal(St, U, U->isPostfix() ? V2 : Result);
// Perform the store.
EvalStore(Dst, U, *I2, St, V1, Result);
Ted Kremenek
committed
}
void GRExprEngine::VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
}
void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A,
AsmStmt::outputs_iterator I,
AsmStmt::outputs_iterator E,
NodeTy* Pred, NodeSet& Dst) {
if (I == E) {
VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
return;
}
NodeSet Tmp;
Zhongxing Xu
committed
VisitLValue(*I, Pred, Tmp);
++I;
for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
}
void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
NodeTy* Pred, NodeSet& Dst) {
if (I == E) {
// We have processed both the inputs and the outputs. All of the outputs
Zhongxing Xu
committed
// should evaluate to Locs. Nuke all of their values.
// FIXME: Some day in the future it would be nice to allow a "plug-in"
// which interprets the inline asm and stores proper results in the
// outputs.
for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
Zhongxing Xu
committed
SVal X = GetSVal(St, *OI);
assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
Zhongxing Xu
committed
if (isa<Loc>(X))
St = SetSVal(St, cast<Loc>(X), UnknownVal());
return;
}
NodeSet Tmp;
Visit(*I, Pred, Tmp);
++I;
for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
}
Ted Kremenek
committed
void GRExprEngine::EvalReturn(NodeSet& Dst, ReturnStmt* S, NodeTy* Pred) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
Ted Kremenek
committed
getTF().EvalReturn(Dst, *this, *Builder, S, Pred);
Ted Kremenek
committed
// Handle the case where no nodes where generated.
Ted Kremenek
committed
if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
Ted Kremenek
committed
MakeNode(Dst, S, Pred, GetState(Pred));
}
void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) {
Expr* R = S->getRetValue();
if (!R) {
Ted Kremenek
committed
EvalReturn(Dst, S, Pred);
return;
}
Ted Kremenek
committed
NodeSet DstRet;
QualType T = R->getType();
if (T->isPointerLikeType()) {
// Check if any of the return values return the address of a stack variable.
NodeSet Tmp;
Visit(R, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
SVal X = GetSVal((*I)->getState(), R);
Zhongxing Xu
committed
if (isa<loc::MemRegionVal>(X)) {
Ted Kremenek
committed
// Determine if the value is on the stack.
Zhongxing Xu
committed
const MemRegion* R = cast<loc::MemRegionVal>(&X)->getRegion();
Ted Kremenek
committed
if (R && getStateManager().hasStackStorage(R)) {
// Create a special node representing the v
NodeTy* RetStackNode = Builder->generateNode(S, GetState(*I), *I);
if (RetStackNode) {
RetStackNode->markAsSink();
RetsStackAddr.insert(RetStackNode);
}
continue;
}
}
Ted Kremenek
committed
DstRet.Add(*I);
}
}
else
Ted Kremenek
committed
Visit(R, Pred, DstRet);
for (NodeSet::iterator I=DstRet.begin(), E=DstRet.end(); I!=E; ++I)
EvalReturn(Dst, S, *I);
}
//===----------------------------------------------------------------------===//
// Transfer functions: Binary operators.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
const GRState* GRExprEngine::CheckDivideZero(Expr* Ex, const GRState* St,
NodeTy* Pred, SVal Denom) {
// Divide by undefined? (potentially zero)
if (Denom.isUndef()) {
NodeTy* DivUndef = Builder->generateNode(Ex, St, Pred);
if (DivUndef) {
DivUndef->markAsSink();
ExplicitBadDivides.insert(DivUndef);
}
Ted Kremenek
committed
return 0;
}
// Check for divide/remainder-by-zero.
// First, "assume" that the denominator is 0 or undefined.
bool isFeasibleZero = false;
const GRState* ZeroSt = Assume(St, Denom, false, isFeasibleZero);