[cfe-commits] r96293 - in /cfe/trunk: include/clang/Checker/PathSensitive/GRExprEngine.h lib/Checker/GRExprEngine.cpp
Ted Kremenek
kremenek at apple.com
Mon Feb 15 15:02:46 PST 2010
Author: kremenek
Date: Mon Feb 15 17:02:46 2010
New Revision: 96293
URL: http://llvm.org/viewvc/llvm-project?rev=96293&view=rev
Log:
Convert GRExprEngine's handling of ObjCMessageExprs to use a worklist
to evaluate arguments.
Modified:
cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
cfe/trunk/lib/Checker/GRExprEngine.cpp
Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=96293&r1=96292&r2=96293&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Mon Feb 15 17:02:46 2010
@@ -328,17 +328,6 @@
void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue);
- void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
- ObjCMessageExpr::arg_iterator I,
- ObjCMessageExpr::arg_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst,
- bool asLValue);
-
- void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue);
-
/// VisitReturnStmt - Transfer function logic for return statements.
void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=96293&r1=96292&r2=96293&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Checker/GRExprEngine.cpp Mon Feb 15 17:02:46 2010
@@ -47,7 +47,7 @@
}
-static QualType GetCalleeReturnType(const CallExpr *CE) {
+static QualType GetCalleeReturnType(const CallExpr *CE) {
const Expr *Callee = CE->getCallee();
QualType T = Callee->getType();
if (const PointerType *PT = T->getAs<PointerType>()) {
@@ -61,7 +61,7 @@
return T;
}
-static bool CalleeReturnsReference(const CallExpr *CE) {
+static bool CalleeReturnsReference(const CallExpr *CE) {
return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
}
@@ -176,10 +176,10 @@
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
- }
+ }
void *tag = I->first;
Checker *checker = I->second;
-
+
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
NI != NE; ++NI)
checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
@@ -190,7 +190,7 @@
// automatically.
}
-void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
ExplodedNodeSet &Dst,
const GRState *state,
ExplodedNode *Pred) {
@@ -219,8 +219,8 @@
// CheckerEvalCall returns true if one of the checkers processed the node.
// This may return void when all call evaluation logic goes to some checker
// in the future.
-bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
- ExplodedNodeSet &Dst,
+bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
ExplodedNode *Pred) {
bool Evaluated = false;
ExplodedNodeSet DstTmp;
@@ -245,21 +245,21 @@
return Evaluated;
}
-// FIXME: This is largely copy-paste from CheckerVisit(). Need to
+// FIXME: This is largely copy-paste from CheckerVisit(). Need to
// unify.
void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
SVal location, SVal val, bool isPrevisit) {
-
+
if (Checkers.empty()) {
Dst.insert(Src);
return;
}
-
+
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
-
+
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
@@ -272,16 +272,16 @@
void *tag = I->first;
Checker *checker = I->second;
-
+
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
NI != NE; ++NI)
checker->GR_VisitBind(*CurrSet, *Builder, *this, AssignE, StoreE,
*NI, tag, location, val, isPrevisit);
-
+
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
-
+
// Don't autotransition. The CheckerContext objects should do this
// automatically.
}
@@ -299,7 +299,7 @@
// explicitly registered with the BugReporter. If they issue any BugReports,
// their associated BugType will get registered with the BugReporter
// automatically. Note that the check itself is owned by the GRExprEngine
- // object.
+ // object.
RegisterAdjustedReturnValueChecker(Eng);
RegisterAttrNonNullChecker(Eng);
RegisterCallAndMessageChecker(Eng);
@@ -336,7 +336,7 @@
BR(mgr, *this), TF(tf) {
// Register internal checks.
RegisterInternalChecks(*this);
-
+
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
TF->RegisterPrinters(getStateManager().Printers);
@@ -375,7 +375,7 @@
// FIXME: It would be nice if we had a more general mechanism to add
// such preconditions. Some day.
do {
- const Decl *D = InitLoc->getDecl();
+ const Decl *D = InitLoc->getDecl();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Precondition: the first argument of 'main' is an integer guaranteed
// to be > 0.
@@ -387,11 +387,11 @@
QualType T = PD->getType();
if (!T->isIntegerType())
break;
-
+
const MemRegion *R = state->getRegion(PD, InitLoc);
if (!R)
break;
-
+
SVal V = state->getSVal(loc::MemRegionVal(R));
SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V,
ValMgr.makeZeroVal(T),
@@ -399,23 +399,23 @@
DefinedOrUnknownSVal *Constraint =
dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
-
+
if (!Constraint)
break;
-
+
if (const GRState *newState = state->Assume(*Constraint, true))
state = newState;
-
+
break;
}
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
// Precondition: 'self' is always non-null upon entry to an Objective-C
// method.
const ImplicitParamDecl *SelfD = MD->getSelfDecl();
const MemRegion *R = state->getRegion(SelfD, InitLoc);
SVal V = state->getSVal(loc::MemRegionVal(R));
-
+
if (const Loc *LV = dyn_cast<Loc>(&V)) {
// Assume that the pointer value in 'self' is non-null.
state = state->Assume(*LV, true);
@@ -423,7 +423,7 @@
}
}
} while (0);
-
+
return state;
}
@@ -434,19 +434,19 @@
/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
- bool assumption) {
+ bool assumption) {
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
I != E; ++I) {
if (!state)
- return NULL;
-
+ return NULL;
+
state = I->second->EvalAssume(state, cond, assumption);
}
-
+
if (!state)
return NULL;
-
+
return TF->EvalAssume(state, cond, assumption);
}
@@ -615,7 +615,7 @@
case Stmt::AsmStmtClass:
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
-
+
case Stmt::BlockDeclRefExprClass:
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false);
break;
@@ -637,7 +637,7 @@
break;
}
- if (AMgr.shouldEagerlyAssume() &&
+ if (AMgr.shouldEagerlyAssume() &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false);
@@ -695,7 +695,7 @@
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
+ break;
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass: {
@@ -703,7 +703,7 @@
VisitCast(C, C->getSubExpr(), Pred, Dst, false);
break;
}
-
+
case Stmt::IfStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
@@ -775,7 +775,7 @@
case Stmt::StringLiteralClass:
VisitLValue(cast<StringLiteral>(S), Pred, Dst);
break;
-
+
case Stmt::SwitchStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
@@ -793,18 +793,18 @@
VisitUnaryOperator(U, Pred, Dst, false);
break;
}
-
+
case Stmt::WhileStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
+ break;
}
}
void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
-
+
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Ex->getLocStart(),
"Error evaluating statement");
@@ -836,27 +836,27 @@
case Stmt::CompoundAssignOperatorClass:
VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::BlockDeclRefExprClass:
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr *C = cast<CallExpr>(Ex);
assert(CalleeReturnsReferenceOrRecord(C));
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
break;
}
-
+
case Stmt::CompoundLiteralExprClass:
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
- return;
+ return;
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass: {
CastExpr *C = cast<CastExpr>(Ex);
@@ -864,7 +864,7 @@
VisitCast(C, C->getSubExpr(), Pred, Dst, true);
break;
}
-
+
case Stmt::MemberExprClass:
VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
return;
@@ -872,11 +872,11 @@
case Stmt::ObjCIvarRefExprClass:
VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::ObjCMessageExprClass: {
ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
assert(ReceiverReturnsReferenceOrRecord(ME));
- VisitObjCMessageExpr(ME, Pred, Dst, true);
+ VisitObjCMessageExpr(ME, Pred, Dst, true);
return;
}
@@ -911,7 +911,7 @@
case Stmt::IntegerLiteralClass:
CreateCXXTemporaryObject(Ex, Pred, Dst);
return;
-
+
default:
// Arbitrary subexpressions can return aggregate temporaries that
// can be used in a lvalue context. We need to enhance our support
@@ -1083,7 +1083,7 @@
SVal recovered = RecoverCastedSymbol(getStateManager(),
builder.getState(), Condition,
getContext());
-
+
if (!recovered.isUnknown()) {
X = recovered;
}
@@ -1165,7 +1165,7 @@
void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
- assert(Ex == CurrentStmt &&
+ assert(Ex == CurrentStmt &&
Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
const GRState* state = GetState(Pred);
@@ -1203,7 +1203,7 @@
if (CondV_untested.isUndef()) {
//ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
- // FIXME: add checker
+ // FIXME: add checker
//UndefBranches.insert(N);
return;
@@ -1247,7 +1247,7 @@
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
CondV, CaseVal);
-
+
// Now "assume" that the case matches.
if (const GRState* stateNew = state->Assume(Res, true)) {
builder.generateCaseStmtNode(I, stateNew);
@@ -1271,7 +1271,7 @@
DefaultSt = NULL;
}
}
-
+
// Concretize the next value in the range.
if (V1.Val.getInt() == V2.Val.getInt())
break;
@@ -1314,7 +1314,7 @@
MakeNode(Dst, B, Pred, state->BindExpr(B, X));
return;
}
-
+
DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
// We took the RHS. Because the value of the '&&' or '||' expression must
@@ -1347,16 +1347,16 @@
void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+
ExplodedNodeSet Tmp;
-
+
CanQualType T = getContext().getCanonicalType(BE->getType());
SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T,
Pred->getLocationContext());
MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
ProgramPoint::PostLValueKind);
-
+
// Post-visit the BlockExpr.
CheckerVisit(BE, Dst, Tmp, false);
}
@@ -1391,7 +1391,7 @@
else
V = UnknownVal();
}
-
+
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
ProgramPoint::PostLValueKind);
}
@@ -1494,19 +1494,19 @@
Stmt* StoreE, ExplodedNode* Pred,
const GRState* state, SVal location, SVal Val,
bool atDeclInit) {
-
-
+
+
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet, Src;
Src.Add(Pred);
CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true);
-
+
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
-
+
if (Pred != *I)
state = GetState(*I);
-
+
const GRState* newState = 0;
if (atDeclInit) {
@@ -1565,7 +1565,7 @@
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
ProgramPoint::PostStoreKind);
SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
-
+
// Proceed with the store.
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
@@ -1578,12 +1578,12 @@
// Are we loading from a region? This actually results in two loads; one
// to fetch the address of the referenced value and one to fetch the
// referenced value.
- if (const TypedRegion *TR =
+ if (const TypedRegion *TR =
dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
-
+
QualType ValTy = TR->getValueType(getContext());
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
- static int loadReferenceTag = 0;
+ static int loadReferenceTag = 0;
ExplodedNodeSet Tmp;
EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
getContext().getPointerType(RT->getPointeeType()));
@@ -1593,11 +1593,11 @@
state = GetState(*I);
location = state->getSVal(Ex);
EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
- }
+ }
return;
}
}
-
+
EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
}
@@ -1605,16 +1605,16 @@
ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag, QualType LoadTy) {
-
+
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
if (Tmp.empty())
return;
-
+
assert(!location.isUndef());
-
+
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
SaveAndRestore<const void*> OldTag(Builder->Tag);
@@ -1627,7 +1627,7 @@
ProgramPoint::PostLoadKind, tag);
}
else {
- SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
+ SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
Ex->getType() : LoadTy);
MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
tag);
@@ -1644,11 +1644,11 @@
Dst.Add(Pred);
return;
}
-
+
ExplodedNodeSet Src, Tmp;
Src.Add(Pred);
ExplodedNodeSet *PrevSet = &Src;
-
+
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
@@ -1658,10 +1658,10 @@
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
}
-
+
void *tag = I->first;
Checker *checker = I->second;
-
+
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
NI != NE; ++NI) {
// Use the 'state' argument only when the predecessor node is the
@@ -1670,7 +1670,7 @@
*NI == Pred ? state : GetState(*NI),
location, tag, isLoad);
}
-
+
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
@@ -1688,7 +1688,7 @@
CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
: I(i), N(n) {}
-};
+};
} // end anonymous namespace
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
@@ -1706,31 +1706,31 @@
llvm::SmallVector<CallExprWLItem, 20> WorkList;
WorkList.reserve(AE - AI);
WorkList.push_back(CallExprWLItem(AI, Pred));
-
+
ExplodedNodeSet ArgsEvaluated;
while (!WorkList.empty()) {
CallExprWLItem Item = WorkList.back();
WorkList.pop_back();
-
+
if (Item.I == AE) {
ArgsEvaluated.insert(Item.N);
continue;
}
-
+
// Evaluate the argument.
ExplodedNodeSet Tmp;
const unsigned ParamIdx = Item.I - AI;
-
+
bool VisitAsLvalue = false;
if (Proto && ParamIdx < Proto->getNumArgs())
VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
+
if (VisitAsLvalue)
VisitLValue(*Item.I, Item.N, Tmp);
else
Visit(*Item.I, Item.N, Tmp);
-
+
// Enqueue evaluating the next argument on the worklist.
++(Item.I);
@@ -1741,32 +1741,32 @@
// Now process the call itself.
ExplodedNodeSet DstTmp;
Expr* Callee = CE->getCallee()->IgnoreParens();
-
+
for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
NE=ArgsEvaluated.end(); NI != NE; ++NI) {
// Evaluate the callee.
ExplodedNodeSet DstTmp2;
- Visit(Callee, *NI, DstTmp2);
+ Visit(Callee, *NI, DstTmp2);
// Perform the previsit of the CallExpr, storing the results in DstTmp.
CheckerVisit(CE, DstTmp, DstTmp2, true);
}
-
+
// Finally, evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
ExplodedNodeSet DstTmp3;
-
+
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
DI != DE; ++DI) {
-
+
const GRState* state = GetState(*DI);
SVal L = state->getSVal(Callee);
-
+
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
ExplodedNodeSet DstChecker;
-
+
// If the callee is processed by a checker, skip the rest logic.
if (CheckerEvalCall(CE, DstChecker, *DI))
DstTmp3.insert(DstChecker);
@@ -1774,17 +1774,17 @@
for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
DE_Checker = DstChecker.end();
DI_Checker != DE_Checker; ++DI_Checker) {
-
+
// Dispatch to the plug-in transfer function.
unsigned OldSize = DstTmp3.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
Pred = *DI_Checker;
-
+
// Dispatch to transfer function logic to handle the call itself.
// FIXME: Allow us to chain together transfer functions.
- assert(Builder && "GRStmtNodeBuilder must be defined.");
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, 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 && DstTmp3.size() == OldSize &&
@@ -1793,24 +1793,24 @@
}
}
}
-
+
// Finally, perform the post-condition check of the CallExpr and store
// the created nodes in 'Dst'.
-
+
if (!(!asLValue && CalleeReturnsReference(CE))) {
CheckerVisit(CE, Dst, DstTmp3, false);
return;
}
-
+
// Handle the case where the called function returns a reference but
// we expect an rvalue. For such cases, convert the reference to
- // an rvalue.
+ // an rvalue.
// FIXME: This conversion doesn't actually happen unless the result
// of CallExpr is consumed by another expression.
ExplodedNodeSet DstTmp4;
CheckerVisit(CE, DstTmp4, DstTmp3, false);
QualType LoadTy = CE->getType();
-
+
static int *ConvertToRvalueTag = 0;
for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end();
NI!=NE; ++NI) {
@@ -1950,10 +1950,10 @@
Stmt* elem = S->getElement();
ExplodedNodeSet Tmp;
EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
-
+
if (Tmp.empty())
return;
-
+
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
Pred = *NI;
const GRState *state = GetState(Pred);
@@ -1993,90 +1993,96 @@
// Transfer function: Objective-C message expressions.
//===----------------------------------------------------------------------===//
+namespace {
+class ObjCMsgWLItem {
+public:
+ ObjCMessageExpr::arg_iterator I;
+ ExplodedNode *N;
+
+ ObjCMsgWLItem(const ObjCMessageExpr::arg_iterator &i, ExplodedNode *n)
+ : I(i), N(n) {}
+};
+} // end anonymous namespace
+
void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue){
- VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
- Pred, Dst, asLValue);
-}
+ // Create a worklist to process both the arguments.
+ llvm::SmallVector<ObjCMsgWLItem, 20> WL;
-void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
- ObjCMessageExpr::arg_iterator AI,
- ObjCMessageExpr::arg_iterator AE,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue) {
- if (AI == AE) {
+ // But first evaluate the receiver (if any).
+ ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
+ if (Expr *Receiver = ME->getReceiver()) {
+ ExplodedNodeSet Tmp;
+ Visit(Receiver, Pred, Tmp);
- // Process the receiver.
+ if (Tmp.empty())
+ return;
- if (Expr* Receiver = ME->getReceiver()) {
- ExplodedNodeSet Tmp;
- Visit(Receiver, Pred, Tmp);
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
+ WL.push_back(ObjCMsgWLItem(AI, *I));
+ }
+ else
+ WL.push_back(ObjCMsgWLItem(AI, Pred));
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE;
- ++NI)
- VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue);
+ // Evaluate the arguments.
+ ExplodedNodeSet ArgsEvaluated;
+ while (!WL.empty()) {
+ ObjCMsgWLItem Item = WL.back();
+ WL.pop_back();
- return;
+ if (Item.I == AE) {
+ ArgsEvaluated.insert(Item.N);
+ continue;
}
- VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(*AI, Pred, Tmp);
+ // Evaluate the subexpression.
+ ExplodedNodeSet Tmp;
- ++AI;
+ // FIXME: [Objective-C++] handle arguments that are references
+ Visit(*Item.I, Item.N, Tmp);
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
- VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue);
-}
+ // Enqueue evaluating the next argument on the worklist.
+ ++(Item.I);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ WL.push_back(ObjCMsgWLItem(Item.I, *NI));
+ }
-void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue) {
+ // Now that the arguments are processed, handle the previsits checks.
+ ExplodedNodeSet DstPrevisit;
+ CheckerVisit(ME, DstPrevisit, ArgsEvaluated, true);
- // Handle previsits checks.
- ExplodedNodeSet Src, DstTmp;
- Src.Add(Pred);
-
- CheckerVisit(ME, DstTmp, Src, true);
-
- ExplodedNodeSet PostVisitSrc;
+ // Proceed with evaluate the message expression.
+ ExplodedNodeSet DstEval;
- for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
- DI!=DE; ++DI) {
+ for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(),
+ DE = DstPrevisit.end(); DI != DE; ++DI) {
Pred = *DI;
bool RaisesException = false;
-
- unsigned OldSize = PostVisitSrc.size();
+ unsigned OldSize = DstEval.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
if (const Expr *Receiver = ME->getReceiver()) {
const GRState *state = Pred->getState();
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal =
+ DefinedOrUnknownSVal receiverVal =
cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
const GRState *notNilState, *nilState;
llvm::tie(notNilState, nilState) = state->Assume(receiverVal);
- // There are three cases: can be nil or non-nil, must be nil, must be
+ // There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We handle must be nil, and merge the rest two into non-nil.
if (nilState && !notNilState) {
- CheckerEvalNilReceiver(ME, PostVisitSrc, nilState, Pred);
+ CheckerEvalNilReceiver(ME, DstEval, nilState, Pred);
continue;
}
- assert(notNilState);
-
// Check if the "raise" message was sent.
+ assert(notNilState);
if (ME->getSelector() == RaiseSel)
RaisesException = true;
@@ -2086,7 +2092,7 @@
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState);
+ EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
else {
IdentifierInfo* ClsName = ME->getClassName();
@@ -2104,7 +2110,8 @@
// Lazily create a cache of the selectors.
if (!NSExceptionInstanceRaiseSelectors) {
ASTContext& Ctx = getContext();
- NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
+ NSExceptionInstanceRaiseSelectors =
+ new Selector[NUM_RAISE_SELECTORS];
llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
unsigned idx = 0;
@@ -2133,36 +2140,35 @@
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred));
+ EvalObjCMessageExpr(DstEval, ME, Pred, Builder->GetState(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 && PostVisitSrc.size() == OldSize &&
+ if (!Builder->BuildSinks && DstEval.size() == OldSize &&
!Builder->HasGeneratedNode)
- MakeNode(PostVisitSrc, ME, Pred, GetState(Pred));
+ MakeNode(DstEval, ME, Pred, GetState(Pred));
}
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
if (!(!asLValue && ReceiverReturnsReference(ME))) {
- CheckerVisit(ME, Dst, PostVisitSrc, false);
+ CheckerVisit(ME, Dst, DstEval, false);
return;
}
-
+
// Handle the case where the message expression returns a reference but
// we expect an rvalue. For such cases, convert the reference to
- // an rvalue.
+ // an rvalue.
// FIXME: This conversion doesn't actually happen unless the result
// of ObjCMessageExpr is consumed by another expression.
ExplodedNodeSet DstRValueConvert;
- CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false);
+ CheckerVisit(ME, DstRValueConvert, DstEval, false);
QualType LoadTy = ME->getType();
-
+
static int *ConvertToRvalueTag = 0;
for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(),
- NE = DstRValueConvert.end();
- NI!=NE; ++NI) {
+ NE = DstRValueConvert.end(); NI != NE; ++NI) {
const GRState *state = GetState(*NI);
EvalLoad(Dst, ME, *NI, state, state->getSVal(ME),
&ConvertToRvalueTag, LoadTy);
@@ -2173,7 +2179,7 @@
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
+void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst, bool asLValue) {
ExplodedNodeSet S1;
QualType T = CastE->getType();
@@ -2296,7 +2302,7 @@
ExplodedNodeSet Tmp2;
CheckerVisit(DS, Tmp2, Tmp, true);
-
+
for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
ExplodedNode *N = *I;
const GRState *state = GetState(N);
@@ -2311,12 +2317,12 @@
// UnknownVal.
if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
-
+
EvalBind(Dst, DS, DS, *I, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
+ loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
}
else {
state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
@@ -2327,26 +2333,26 @@
void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S,
ExplodedNode *Pred, ExplodedNodeSet& Dst) {
-
- Expr* InitEx = VD->getInit();
+
+ Expr* InitEx = VD->getInit();
ExplodedNodeSet Tmp;
Visit(InitEx, Pred, Tmp);
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
ExplodedNode *N = *I;
const GRState *state = GetState(N);
-
+
const LocationContext *LC = N->getLocationContext();
SVal InitVal = state->getSVal(InitEx);
-
+
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
-
+
EvalBind(Dst, S, S, N, state,
loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
}
@@ -2480,7 +2486,7 @@
amt = getContext().getTypeAlignInChars(T);
MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex,
+ GetState(Pred)->BindExpr(Ex,
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
@@ -2569,7 +2575,7 @@
assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
assert(U->getType()->isIntegerType());
assert(IV.isSigned() == U->getType()->isSignedIntegerType());
- SVal X = ValMgr.makeIntVal(IV);
+ SVal X = ValMgr.makeIntVal(IV);
MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
return;
}
@@ -2717,7 +2723,7 @@
if (V2_untested.isUnknownOrUndef()) {
MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
continue;
- }
+ }
DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
// Handle all other values.
@@ -2772,19 +2778,19 @@
}
-void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst) {
// Get the this object region from StoreManager.
const MemRegion *R =
ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
Pred->getLocationContext());
-
+
const GRState *state = GetState(Pred);
SVal V = state->getSVal(loc::MemRegionVal(R));
MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
}
-void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
+void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
}
@@ -2810,7 +2816,7 @@
void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
- ExplodedNode* Pred,
+ ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
if (I == E) {
@@ -2848,7 +2854,7 @@
void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+
ExplodedNodeSet Src;
if (Expr *RetE = RS->getRetValue()) {
Visit(RetE, Pred, Src);
@@ -2856,25 +2862,25 @@
else {
Src.Add(Pred);
}
-
+
ExplodedNodeSet CheckedSet;
CheckerVisit(RS, CheckedSet, Src, true);
-
+
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I != E; ++I) {
assert(Builder && "GRStmtNodeBuilder must be defined.");
-
+
Pred = *I;
unsigned size = Dst.size();
-
+
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
-
+
getTF().EvalReturn(Dst, *this, *Builder, RS, Pred);
-
- // Handle the case where no nodes where generated.
- if (!Builder->BuildSinks && Dst.size() == size &&
+
+ // Handle the case where no nodes where generated.
+ if (!Builder->BuildSinks && Dst.size() == size &&
!Builder->HasGeneratedNode)
MakeNode(Dst, RS, Pred, GetState(Pred));
}
@@ -2928,7 +2934,7 @@
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
QualType T = RHS->getType();
-
+
if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV))
&& (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) {
unsigned Count = Builder->getCurrentBlockCount();
@@ -2942,12 +2948,12 @@
EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
continue;
}
-
+
if (!B->isAssignmentOp()) {
// Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr).
SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
-
+
if (Result.isUnknown()) {
if (OldSt != state) {
// Generate a new node if we have already created a new state.
@@ -2955,12 +2961,12 @@
}
else
Tmp3.Add(*I2);
-
+
continue;
}
-
+
state = state->BindExpr(B, Result);
-
+
MakeNode(Tmp3, B, *I2, state);
continue;
}
@@ -3047,24 +3053,24 @@
CheckerVisit(B, Dst, Tmp3, false);
}
-void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
const GRState *state = GetState(*I);
-
+
// Bind the temporary object to the value of the expression. Then bind
// the expression to the location of the object.
SVal V = state->getSVal(Ex);
- const MemRegion *R =
+ const MemRegion *R =
ValMgr.getRegionManager().getCXXObjectRegion(Ex,
Pred->getLocationContext());
state = state->bindLoc(loc::MemRegionVal(R), V);
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
- }
+ }
}
//===----------------------------------------------------------------------===//
More information about the cfe-commits
mailing list