Newer
Older
const GRState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
// Check for loads/stores from/to undefined values.
if (location.isUndef()) {
ProgramPoint::Kind K =
isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind;
if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, K)) {
Succ->markAsSink();
UndefDeref.insert(Succ);
}
return NULL;
}
// 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)
{
// Determine the type of function we're calling (if available).
const FunctionTypeProto *Proto = NULL;
QualType FnType = CE->getCallee()->IgnoreParens()->getType();
if (const PointerType *FnTypePtr = FnType->getAsPointerType())
Proto = FnTypePtr->getPointeeType()->getAsFunctionTypeProto();
VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0);
}
void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
NodeSet& Dst, const FunctionTypeProto *Proto,
unsigned ParamIdx) {
// Process the arguments.
if (AI != AE) {
// If the call argument is being bound to a reference parameter,
// visit it as an lvalue, not an rvalue.
bool VisitAsLvalue = false;
if (Proto && ParamIdx < Proto->getNumArgs())
VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
NodeSet DstTmp;
if (VisitAsLvalue)
VisitLValue(*AI, Pred, DstTmp);
else
Visit(*AI, Pred, DstTmp);
++AI;
for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI)
VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1);
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;
if (!memcmp(s, "dtrace_assfail", 14) ||
!memcmp(s, "yy_fatal_error", 14))
Builder->BuildSinks = true;
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()));
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);
else
EvalLoad(Dst, Ex, *I, St, location);
}
}
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
//===----------------------------------------------------------------------===//
// 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
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
// 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 (const ExplicitCastExpr *ExCast = dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
if (ExTy->isArrayType() || ExTy->isFunctionType() || 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()) {
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()) {
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);
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();
Ted Kremenek
committed
continue;
}
Zhongxing Xu
committed
// StoreManager casts array to different values.
if (ExTy->isArrayType()) {
Ted Kremenek
committed
assert(T->isPointerType() || T->isReferenceType());
Zhongxing Xu
committed
V = StateMgr.ArrayToPointer(V);
Zhongxing Xu
committed
continue;
}
Ted Kremenek
committed
// All other cases.
MakeNode(Dst, CastE, N, BindExpr(St, CastE, EvalCast(V, CastE->getType())));
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL,
NodeTy* Pred, NodeSet& Dst) {
// FIXME: Can getInitializer() be NULL?
InitListExpr* ILE = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
NodeSet Tmp;
Visit(ILE, Pred, Tmp);
for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
// Retrieve the initializer values from the environment and store them
// into a vector that will then be handed off to the Store.
const GRState* St = GetState(*I);
llvm::SmallVector<SVal, 10> IVals;
IVals.reserve(ILE->getNumInits());
for (Stmt::child_iterator J=ILE->child_begin(), EJ=ILE->child_end();
J!=EJ; ++J)
IVals.push_back(GetSVal(St, cast<Expr>(*J)));
const CompoundLiteralRegion* R =
StateMgr.getRegionManager().getCompoundLiteralRegion(CL);
assert (!IVals.empty() && "Initializer cannot be empty.");
St = StateMgr.BindCompoundLiteral(St, R, &IVals[0], &IVals[0]+IVals.size());
}
}
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);
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.BindDecl(St, VD, Ex, Builder->getCurrentBlockCount());
}
}
namespace {
// This class is used by VisitInitListExpr as an item in a worklist
// for processing the values contained in an InitListExpr.
class VISIBILITY_HIDDEN InitListWLItem {
public:
llvm::ImmutableList<SVal> Vals;
GRExprEngine::NodeTy* N;
InitListExpr::reverse_iterator Itr;
InitListWLItem(GRExprEngine::NodeTy* n, llvm::ImmutableList<SVal> vals,
InitListExpr::reverse_iterator itr)
: Vals(vals), N(n), Itr(itr) {}
};
}
Zhongxing Xu
committed
void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred,
NodeSet& Dst) {
const GRState* state = GetState(Pred);
QualType T = E->getType();
unsigned NumInitElements = E->getNumInits();
Zhongxing Xu
committed
if (T->isArrayType() || T->isStructureType()) {
Zhongxing Xu
committed
llvm::SmallVector<InitListWLItem, 10> WorkList;
WorkList.reserve(NumInitElements);
WorkList.push_back(InitListWLItem(Pred, getBasicVals().getEmptySValList(),
E->rbegin()));
InitListExpr::reverse_iterator ItrEnd = E->rend();
while (!WorkList.empty()) {
InitListWLItem X = WorkList.back();
WorkList.pop_back();
NodeSet Tmp;
Visit(*X.Itr, X.N, Tmp);
InitListExpr::reverse_iterator NewItr = X.Itr + 1;
Zhongxing Xu
committed
for (NodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
// Get the last initializer value.
state = GetState(*NI);
SVal InitV = GetSVal(state, cast<Expr>(*X.Itr));
// Construct the new list of values by prepending the new value to
// the already constructed list.
llvm::ImmutableList<SVal> NewVals =
getBasicVals().consVals(InitV, X.Vals);
if (NewItr == ItrEnd) {
// Now we have a list holding all init values. Make CompoundSValData.
SVal V = NonLoc::MakeCompoundVal(T, NewVals, getBasicVals());
Zhongxing Xu
committed
// Make final state and node.
MakeNode(Dst, E, Pred, BindExpr(state, E, V));
}
else {
// Still some initializer values to go. Push them onto the worklist.
WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr));
}
}
}
Zhongxing Xu
committed
}
if (Loc::IsLocType(T) || T->isIntegerType()) {
assert (E->getNumInits() == 1);
NodeSet Tmp;
Expr* Init = E->getInit(0);
Visit(Init, Pred, Tmp);
for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) {
state = GetState(*I);
Zhongxing Xu
committed
}
return;
}
if (T->isUnionType()) {
// FIXME: to be implemented.
MakeNode(Dst, E, Pred, state);
return;
}
printf("InitListExpr type = %s\n", T.getAsString().c_str());
assert(0 && "unprocessed InitListExpr type");
}
/// 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;
BindExpr(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)
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());
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());
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) {
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);
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()) {
continue;
}
switch (U->getOpcode()) {
default:
assert(false && "Invalid Opcode.");
break;
case UnaryOperator::Not:
Ted Kremenek
committed
// FIXME: Do we need to handle promotions?
break;
case UnaryOperator::Minus:
Ted Kremenek
committed
// FIXME: Do we need to handle promotions?
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);
}
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 = BindExpr(St, U, NonLoc::MakeVal(getBasicVals(), size, U->getType()));
Ted Kremenek
committed
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;
St = BindExpr(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()) {
continue;
}