1 //=-- ExprEngineObjC.cpp - ExprEngine support for Objective-C ---*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines ExprEngine's support for Objective-C expressions.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
15 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
17 #include "clang/Analysis/Support/SaveAndRestore.h"
19 using namespace clang;
22 void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
24 ExplodedNodeSet &Dst) {
26 const ProgramState *state = Pred->getState();
27 SVal baseVal = state->getSVal(Ex->getBase());
28 SVal location = state->getLValue(Ex->getDecl(), baseVal);
30 ExplodedNodeSet dstIvar;
31 MakeNode(dstIvar, Ex, Pred, state->BindExpr(Ex, location));
33 // Perform the post-condition check of the ObjCIvarRefExpr and store
34 // the created nodes in 'Dst'.
35 getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
38 void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
40 ExplodedNodeSet &Dst) {
41 getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
44 void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
46 ExplodedNodeSet &Dst) {
48 // ObjCForCollectionStmts are processed in two places. This method
49 // handles the case where an ObjCForCollectionStmt* occurs as one of the
50 // statements within a basic block. This transfer function does two things:
52 // (1) binds the next container value to 'element'. This creates a new
53 // node in the ExplodedGraph.
55 // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
56 // whether or not the container has any more elements. This value
57 // will be tested in ProcessBranch. We need to explicitly bind
58 // this value because a container can contain nil elements.
60 // FIXME: Eventually this logic should actually do dispatches to
61 // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
62 // This will require simulating a temporary NSFastEnumerationState, either
63 // through an SVal or through the use of MemRegions. This value can
64 // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
65 // terminates we reclaim the temporary (it goes out of scope) and we
66 // we can test if the SVal is 0 or if the MemRegion is null (depending
67 // on what approach we take).
69 // For now: simulate (1) by assigning either a symbol or nil if the
70 // container is empty. Thus this transfer function will by default
71 // result in state splitting.
73 const Stmt *elem = S->getElement();
74 const ProgramState *state = Pred->getState();
77 if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
78 const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
79 assert(elemD->getInit() == 0);
80 elementV = state->getLValue(elemD, Pred->getLocationContext());
83 elementV = state->getSVal(elem);
86 ExplodedNodeSet dstLocation;
87 evalLocation(dstLocation, elem, Pred, state, elementV, NULL, false);
89 if (dstLocation.empty())
92 for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
93 NE = dstLocation.end(); NI!=NE; ++NI) {
95 const ProgramState *state = Pred->getState();
97 // Handle the case where the container still has elements.
98 SVal TrueV = svalBuilder.makeTruthVal(1);
99 const ProgramState *hasElems = state->BindExpr(S, TrueV);
101 // Handle the case where the container has no elements.
102 SVal FalseV = svalBuilder.makeTruthVal(0);
103 const ProgramState *noElems = state->BindExpr(S, FalseV);
105 if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
106 if (const TypedValueRegion *R =
107 dyn_cast<TypedValueRegion>(MV->getRegion())) {
108 // FIXME: The proper thing to do is to really iterate over the
109 // container. We will do this with dispatch logic to the store.
110 // For now, just 'conjure' up a symbolic value.
111 QualType T = R->getValueType();
112 assert(Loc::isLocType(T));
113 unsigned Count = Builder->getCurrentBlockCount();
114 SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
115 SVal V = svalBuilder.makeLoc(Sym);
116 hasElems = hasElems->bindLoc(elementV, V);
118 // Bind the location to 'nil' on the false branch.
119 SVal nilV = svalBuilder.makeIntVal(0, T);
120 noElems = noElems->bindLoc(elementV, nilV);
123 // Create the new nodes.
124 MakeNode(Dst, S, Pred, hasElems);
125 MakeNode(Dst, S, Pred, noElems);
129 void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
131 ExplodedNodeSet &Dst) {
133 // Handle the previsits checks.
134 ExplodedNodeSet dstPrevisit;
135 getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
138 // Proceed with evaluate the message expression.
139 ExplodedNodeSet dstEval;
141 for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
142 DE = dstPrevisit.end(); DI != DE; ++DI) {
144 ExplodedNode *Pred = *DI;
145 bool RaisesException = false;
146 SaveAndRestore<bool> OldSink(Builder->BuildSinks);
147 SaveOr OldHasGen(Builder->hasGeneratedNode);
149 if (const Expr *Receiver = msg.getInstanceReceiver()) {
150 const ProgramState *state = Pred->getState();
151 SVal recVal = state->getSVal(Receiver);
152 if (!recVal.isUndef()) {
153 // Bifurcate the state into nil and non-nil ones.
154 DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
156 const ProgramState *notNilState, *nilState;
157 llvm::tie(notNilState, nilState) = state->assume(receiverVal);
159 // There are three cases: can be nil or non-nil, must be nil, must be
160 // non-nil. We ignore must be nil, and merge the rest two into non-nil.
161 if (nilState && !notNilState) {
162 dstEval.insert(Pred);
166 // Check if the "raise" message was sent.
168 if (msg.getSelector() == RaiseSel)
169 RaisesException = true;
171 // Check if we raise an exception. For now treat these as sinks.
172 // Eventually we will want to handle exceptions properly.
174 Builder->BuildSinks = true;
176 // Dispatch to plug-in transfer function.
177 evalObjCMessage(dstEval, msg, Pred, notNilState);
180 else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
181 IdentifierInfo* ClsName = Iface->getIdentifier();
182 Selector S = msg.getSelector();
184 // Check for special instance methods.
185 if (!NSExceptionII) {
186 ASTContext &Ctx = getContext();
187 NSExceptionII = &Ctx.Idents.get("NSException");
190 if (ClsName == NSExceptionII) {
191 enum { NUM_RAISE_SELECTORS = 2 };
193 // Lazily create a cache of the selectors.
194 if (!NSExceptionInstanceRaiseSelectors) {
195 ASTContext &Ctx = getContext();
196 NSExceptionInstanceRaiseSelectors =
197 new Selector[NUM_RAISE_SELECTORS];
198 SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
202 II.push_back(&Ctx.Idents.get("raise"));
203 II.push_back(&Ctx.Idents.get("format"));
204 NSExceptionInstanceRaiseSelectors[idx++] =
205 Ctx.Selectors.getSelector(II.size(), &II[0]);
207 // raise:format::arguments:
208 II.push_back(&Ctx.Idents.get("arguments"));
209 NSExceptionInstanceRaiseSelectors[idx++] =
210 Ctx.Selectors.getSelector(II.size(), &II[0]);
213 for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
214 if (S == NSExceptionInstanceRaiseSelectors[i]) {
215 RaisesException = true;
220 // Check if we raise an exception. For now treat these as sinks.
221 // Eventually we will want to handle exceptions properly.
223 Builder->BuildSinks = true;
225 // Dispatch to plug-in transfer function.
226 evalObjCMessage(dstEval, msg, Pred, Pred->getState());
229 assert(Builder->BuildSinks || Builder->hasGeneratedNode);
232 // Finally, perform the post-condition check of the ObjCMessageExpr and store
233 // the created nodes in 'Dst'.
234 getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
237 void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
239 const ProgramState *state) {
240 assert (Builder && "StmtNodeBuilder must be defined.");
242 // First handle the return value.
243 SVal ReturnValue = UnknownVal();
245 // Some method families have known return values.
246 switch (msg.getMethodFamily()) {
249 case OMF_autorelease:
252 // These methods return their receivers.
253 const Expr *ReceiverE = msg.getInstanceReceiver();
255 ReturnValue = state->getSVal(ReceiverE);
260 // If we failed to figure out the return value, use a conjured value instead.
261 if (ReturnValue.isUnknown()) {
262 SValBuilder &SVB = getSValBuilder();
263 QualType ResultTy = msg.getResultType(getContext());
264 unsigned Count = Builder->getCurrentBlockCount();
265 const Expr *CurrentE = cast<Expr>(currentStmt);
266 ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, ResultTy, Count);
269 // Bind the return value.
270 state = state->BindExpr(currentStmt, ReturnValue);
272 // Invalidate the arguments (and the receiver)
273 const LocationContext *LC = Pred->getLocationContext();
274 state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC);
276 // And create the new node.
277 MakeNode(Dst, msg.getOriginExpr(), Pred, state);