ExprEngineObjC.cpp revision 9dc5167e4017ef4c8b327abb6f72225eec2e0f19
1402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//=-- ExprEngineObjC.cpp - ExprEngine support for Objective-C ---*- C++ -*-===//
2402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//
3402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//                     The LLVM Compiler Infrastructure
4402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//
5402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// This file is distributed under the University of Illinois Open Source
6402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// License. See LICENSE.TXT for details.
7402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//
8402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//===----------------------------------------------------------------------===//
9402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//
10402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//  This file defines ExprEngine's support for Objective-C expressions.
11402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//
12402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//===----------------------------------------------------------------------===//
13402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
14402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll#include "clang/AST/StmtObjC.h"
15402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll#include "clang/StaticAnalyzer/Core/CheckerManager.h"
16402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
17402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
18402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
19402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Mollusing namespace clang;
20402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Mollusing namespace ento;
21402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
22402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Mollvoid ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
23402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                          ExplodedNode *Pred,
24402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                          ExplodedNodeSet &Dst) {
25402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  ProgramStateRef state = Pred->getState();
26402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  const LocationContext *LCtx = Pred->getLocationContext();
27402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
28402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  SVal location = state->getLValue(Ex->getDecl(), baseVal);
29402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
30402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  ExplodedNodeSet dstIvar;
31402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  StmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext);
32402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
33402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
34402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // Perform the post-condition check of the ObjCIvarRefExpr and store
35402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // the created nodes in 'Dst'.
36402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
37402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll}
38402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
39402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Mollvoid ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
40402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                             ExplodedNode *Pred,
41402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                             ExplodedNodeSet &Dst) {
42402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
43402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll}
44402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
45402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Mollvoid ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
46402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                            ExplodedNode *Pred,
47402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                            ExplodedNodeSet &Dst) {
48402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
49402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // ObjCForCollectionStmts are processed in two places.  This method
50402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // handles the case where an ObjCForCollectionStmt* occurs as one of the
51402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // statements within a basic block.  This transfer function does two things:
52402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //
53402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //  (1) binds the next container value to 'element'.  This creates a new
54402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //      node in the ExplodedGraph.
55402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //
56402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //  (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
57402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //      whether or not the container has any more elements.  This value
58402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //      will be tested in ProcessBranch.  We need to explicitly bind
59402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //      this value because a container can contain nil elements.
60402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //
61402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // FIXME: Eventually this logic should actually do dispatches to
62402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //   'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
63402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //   This will require simulating a temporary NSFastEnumerationState, either
64402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //   through an SVal or through the use of MemRegions.  This value can
65402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //   be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
66402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //   terminates we reclaim the temporary (it goes out of scope) and we
67402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //   we can test if the SVal is 0 or if the MemRegion is null (depending
68402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //   on what approach we take).
69402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //
70402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //  For now: simulate (1) by assigning either a symbol or nil if the
71402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //    container is empty.  Thus this transfer function will by default
72402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  //    result in state splitting.
73402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
74402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  const Stmt *elem = S->getElement();
75402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  ProgramStateRef state = Pred->getState();
76402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  SVal elementV;
77402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
78402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
79402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
80402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    assert(elemD->getInit() == 0);
81402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    elementV = state->getLValue(elemD, Pred->getLocationContext());
82402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  }
83402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  else {
84402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    elementV = state->getSVal(elem, Pred->getLocationContext());
85402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  }
86402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
87402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  ExplodedNodeSet dstLocation;
88402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
89402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
90402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  ExplodedNodeSet Tmp;
91402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
92402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
93402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
94402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll       NE = dstLocation.end(); NI!=NE; ++NI) {
95402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    Pred = *NI;
96402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    ProgramStateRef state = Pred->getState();
97402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    const LocationContext *LCtx = Pred->getLocationContext();
98402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
99402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    // Handle the case where the container still has elements.
100402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    SVal TrueV = svalBuilder.makeTruthVal(1);
101402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV);
102402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
103402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    // Handle the case where the container has no elements.
104402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    SVal FalseV = svalBuilder.makeTruthVal(0);
105402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
106402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
107402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
108402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll      if (const TypedValueRegion *R =
109402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll          dyn_cast<TypedValueRegion>(MV->getRegion())) {
110402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        // FIXME: The proper thing to do is to really iterate over the
111402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        //  container.  We will do this with dispatch logic to the store.
112402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        //  For now, just 'conjure' up a symbolic value.
113402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        QualType T = R->getValueType();
114402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        assert(Loc::isLocType(T));
115402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        unsigned Count = currentBuilderContext->getCurrentBlockCount();
116402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        SymbolRef Sym = SymMgr.getConjuredSymbol(elem, LCtx, T, Count);
117402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        SVal V = svalBuilder.makeLoc(Sym);
118402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        hasElems = hasElems->bindLoc(elementV, V);
119402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
120402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        // Bind the location to 'nil' on the false branch.
121402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        SVal nilV = svalBuilder.makeIntVal(0, T);
122402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll        noElems = noElems->bindLoc(elementV, nilV);
123402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll      }
124402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
125402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    // Create the new nodes.
126402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    Bldr.generateNode(S, Pred, hasElems);
127402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    Bldr.generateNode(S, Pred, noElems);
128402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  }
129402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
130402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // Finally, run any custom checkers.
131402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
132402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
133402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll}
134402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
135402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Mollstatic bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
136402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  if (!Class)
137402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    return false;
138402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  if (Class->getIdentifier() == II)
139402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll    return true;
140402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll  return isSubclass(Class->getSuperClass(), II);
141402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll}
142402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll
143402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Mollvoid ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
144402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                  ExplodedNode *Pred,
145402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll                                  ExplodedNodeSet &Dst) {
146
147  // Handle the previsits checks.
148  ExplodedNodeSet dstPrevisit;
149  getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
150                                                   msg, *this);
151  ExplodedNodeSet dstGenericPrevisit;
152  getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
153                                            msg, *this);
154
155  // Proceed with evaluate the message expression.
156  ExplodedNodeSet dstEval;
157  StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
158
159  for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
160       DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
161    ExplodedNode *Pred = *DI;
162
163    if (msg.isInstanceMessage()) {
164      SVal recVal = msg.getReceiverSVal();
165      if (!recVal.isUndef()) {
166        // Bifurcate the state into nil and non-nil ones.
167        DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
168
169        ProgramStateRef state = Pred->getState();
170        ProgramStateRef notNilState, nilState;
171        llvm::tie(notNilState, nilState) = state->assume(receiverVal);
172
173        // There are three cases: can be nil or non-nil, must be nil, must be
174        // non-nil. We ignore must be nil, and merge the rest two into non-nil.
175        // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
176        // Revisit once we have lazier constraints.
177        if (nilState && !notNilState) {
178          continue;
179        }
180
181        // Check if the "raise" message was sent.
182        assert(notNilState);
183        if (msg.getSelector() == RaiseSel) {
184          // If we raise an exception, for now treat it as a sink.
185          // Eventually we will want to handle exceptions properly.
186          Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
187          continue;
188        }
189
190        // Generate a transition to non-Nil state.
191        if (notNilState != state)
192          Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
193      }
194    } else {
195      // Check for special class methods.
196      if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
197        if (!NSExceptionII) {
198          ASTContext &Ctx = getContext();
199          NSExceptionII = &Ctx.Idents.get("NSException");
200        }
201
202        if (isSubclass(Iface, NSExceptionII)) {
203          enum { NUM_RAISE_SELECTORS = 2 };
204
205          // Lazily create a cache of the selectors.
206          if (!NSExceptionInstanceRaiseSelectors) {
207            ASTContext &Ctx = getContext();
208            NSExceptionInstanceRaiseSelectors =
209              new Selector[NUM_RAISE_SELECTORS];
210            SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
211            unsigned idx = 0;
212
213            // raise:format:
214            II.push_back(&Ctx.Idents.get("raise"));
215            II.push_back(&Ctx.Idents.get("format"));
216            NSExceptionInstanceRaiseSelectors[idx++] =
217              Ctx.Selectors.getSelector(II.size(), &II[0]);
218
219            // raise:format:arguments:
220            II.push_back(&Ctx.Idents.get("arguments"));
221            NSExceptionInstanceRaiseSelectors[idx++] =
222              Ctx.Selectors.getSelector(II.size(), &II[0]);
223          }
224
225          Selector S = msg.getSelector();
226          bool RaisesException = false;
227          for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
228            if (S == NSExceptionInstanceRaiseSelectors[i]) {
229              RaisesException = true;
230              break;
231            }
232          }
233          if (RaisesException) {
234            // If we raise an exception, for now treat it as a sink.
235            // Eventually we will want to handle exceptions properly.
236            Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
237            continue;
238          }
239
240        }
241      }
242    }
243    // Evaluate the call.
244    defaultEvalCall(Bldr, Pred, msg);
245
246  }
247
248  ExplodedNodeSet dstPostvisit;
249  getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, msg, *this);
250
251  // Finally, perform the post-condition check of the ObjCMessageExpr and store
252  // the created nodes in 'Dst'.
253  getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
254                                                    msg, *this);
255}
256