summaryrefslogtreecommitdiffstats
path: root/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
committerdim <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
commit554bcb69c2d785a011a30e7db87a36a87fe7db10 (patch)
tree9abb1a658a297776086f4e0dfa6ca533de02104e /lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
parentbb67ca86b31f67faee50bd10c3b036d65751745a (diff)
downloadFreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.zip
FreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.tar.gz
Vendor import of clang trunk r161861:
http://llvm.org/svn/llvm-project/cfe/trunk@161861
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngineObjC.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp211
1 files changed, 99 insertions, 112 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index c8ad70a..e3bc498 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -13,8 +13,8 @@
#include "clang/AST/StmtObjC.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
using namespace clang;
using namespace ento;
@@ -74,7 +74,6 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
const Stmt *elem = S->getElement();
ProgramStateRef state = Pred->getState();
SVal elementV;
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
@@ -86,10 +85,11 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
}
ExplodedNodeSet dstLocation;
- Bldr.takeNodes(Pred);
evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
- Bldr.addNodes(dstLocation);
-
+
+ ExplodedNodeSet Tmp;
+ StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+
for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
NE = dstLocation.end(); NI!=NE; ++NI) {
Pred = *NI;
@@ -126,148 +126,135 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
Bldr.generateNode(S, Pred, hasElems);
Bldr.generateNode(S, Pred, noElems);
}
+
+ // Finally, run any custom checkers.
+ // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+}
+
+static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
+ if (!Class)
+ return false;
+ if (Class->getIdentifier() == II)
+ return true;
+ return isSubclass(Class->getSuperClass(), II);
}
-void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
+void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<ObjCMethodCall> Msg =
+ CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
+
// Handle the previsits checks.
ExplodedNodeSet dstPrevisit;
- getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
- msg, *this);
-
+ getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
+ *Msg, *this);
+ ExplodedNodeSet dstGenericPrevisit;
+ getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
+ *Msg, *this);
+
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
- StmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext);
+ StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
- for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
- DE = dstPrevisit.end(); DI != DE; ++DI) {
-
+ for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
+ DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
ExplodedNode *Pred = *DI;
- bool RaisesException = false;
+ ProgramStateRef State = Pred->getState();
+ CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
- if (const Expr *Receiver = msg.getInstanceReceiver()) {
- ProgramStateRef state = Pred->getState();
- SVal recVal = state->getSVal(Receiver, Pred->getLocationContext());
+ if (UpdatedMsg->isInstanceMessage()) {
+ SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
ProgramStateRef notNilState, nilState;
- llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+ llvm::tie(notNilState, nilState) = State->assume(receiverVal);
// There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We ignore must be nil, and merge the rest two into non-nil.
+ // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
+ // Revisit once we have lazier constraints.
if (nilState && !notNilState) {
continue;
}
// Check if the "raise" message was sent.
assert(notNilState);
- if (msg.getSelector() == RaiseSel)
- RaisesException = true;
+ if (Msg->getSelector() == RaiseSel) {
+ // If we raise an exception, for now treat it as a sink.
+ // Eventually we will want to handle exceptions properly.
+ Bldr.generateNode(currentStmt, Pred, State, true);
+ continue;
+ }
- // If we raise an exception, for now treat it as a sink.
- // Eventually we will want to handle exceptions properly.
- // Dispatch to plug-in transfer function.
- evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException);
- }
- }
- else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
- IdentifierInfo* ClsName = Iface->getIdentifier();
- Selector S = msg.getSelector();
-
- // Check for special instance methods.
- if (!NSExceptionII) {
- ASTContext &Ctx = getContext();
- NSExceptionII = &Ctx.Idents.get("NSException");
+ // Generate a transition to non-Nil state.
+ if (notNilState != State)
+ Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
}
-
- if (ClsName == NSExceptionII) {
- enum { NUM_RAISE_SELECTORS = 2 };
-
- // Lazily create a cache of the selectors.
- if (!NSExceptionInstanceRaiseSelectors) {
+ } else {
+ // Check for special class methods.
+ if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
+ if (!NSExceptionII) {
ASTContext &Ctx = getContext();
- NSExceptionInstanceRaiseSelectors =
- new Selector[NUM_RAISE_SELECTORS];
- 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"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
-
- // raise:format::arguments:
- II.push_back(&Ctx.Idents.get("arguments"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
+ NSExceptionII = &Ctx.Idents.get("NSException");
}
- for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
- if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true;
- break;
+ if (isSubclass(Iface, NSExceptionII)) {
+ enum { NUM_RAISE_SELECTORS = 2 };
+
+ // Lazily create a cache of the selectors.
+ if (!NSExceptionInstanceRaiseSelectors) {
+ ASTContext &Ctx = getContext();
+ NSExceptionInstanceRaiseSelectors =
+ new Selector[NUM_RAISE_SELECTORS];
+ 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"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
+
+ // raise:format:arguments:
+ II.push_back(&Ctx.Idents.get("arguments"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
}
+
+ Selector S = Msg->getSelector();
+ bool RaisesException = false;
+ for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
+ if (S == NSExceptionInstanceRaiseSelectors[i]) {
+ RaisesException = true;
+ break;
+ }
+ }
+ if (RaisesException) {
+ // If we raise an exception, for now treat it as a sink.
+ // Eventually we will want to handle exceptions properly.
+ Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
+ continue;
+ }
+
+ }
}
-
- // If we raise an exception, for now treat it as a sink.
- // Eventually we will want to handle exceptions properly.
- // Dispatch to plug-in transfer function.
- evalObjCMessage(Bldr, msg, Pred, Pred->getState(), RaisesException);
}
+
+ // Evaluate the call.
+ defaultEvalCall(Bldr, Pred, *UpdatedMsg);
}
+ ExplodedNodeSet dstPostvisit;
+ getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
+ *Msg, *this);
+
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
- getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
+ getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
+ *Msg, *this);
}
-
-void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
- const ObjCMessage &msg,
- ExplodedNode *Pred,
- ProgramStateRef state,
- bool GenSink) {
- // First handle the return value.
- SVal ReturnValue = UnknownVal();
-
- // Some method families have known return values.
- switch (msg.getMethodFamily()) {
- default:
- break;
- case OMF_autorelease:
- case OMF_retain:
- case OMF_self: {
- // These methods return their receivers.
- const Expr *ReceiverE = msg.getInstanceReceiver();
- if (ReceiverE)
- ReturnValue = state->getSVal(ReceiverE, Pred->getLocationContext());
- break;
- }
- }
-
- // If we failed to figure out the return value, use a conjured value instead.
- if (ReturnValue.isUnknown()) {
- SValBuilder &SVB = getSValBuilder();
- QualType ResultTy = msg.getResultType(getContext());
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- const Expr *CurrentE = cast<Expr>(currentStmt);
- const LocationContext *LCtx = Pred->getLocationContext();
- ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy, Count);
- }
-
- // Bind the return value.
- const LocationContext *LCtx = Pred->getLocationContext();
- state = state->BindExpr(currentStmt, LCtx, ReturnValue);
-
- // Invalidate the arguments (and the receiver)
- state = invalidateArguments(state, CallOrObjCMessage(msg, state, LCtx), LCtx);
-
- // And create the new node.
- Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);
- assert(Bldr.hasGeneratedNodes());
-}
-
OpenPOWER on IntegriCloud