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