clang API Documentation

ExprEngineObjC.cpp
Go to the documentation of this file.
00001 //=-- ExprEngineObjC.cpp - ExprEngine support for Objective-C ---*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines ExprEngine's support for Objective-C expressions.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "clang/AST/StmtObjC.h"
00015 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
00016 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
00017 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
00018 
00019 using namespace clang;
00020 using namespace ento;
00021 
00022 void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex, 
00023                                           ExplodedNode *Pred,
00024                                           ExplodedNodeSet &Dst) {
00025   ProgramStateRef state = Pred->getState();
00026   const LocationContext *LCtx = Pred->getLocationContext();
00027   SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
00028   SVal location = state->getLValue(Ex->getDecl(), baseVal);
00029   
00030   ExplodedNodeSet dstIvar;
00031   StmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext);
00032   Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
00033   
00034   // Perform the post-condition check of the ObjCIvarRefExpr and store
00035   // the created nodes in 'Dst'.
00036   getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
00037 }
00038 
00039 void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
00040                                              ExplodedNode *Pred,
00041                                              ExplodedNodeSet &Dst) {
00042   getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
00043 }
00044 
00045 void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
00046                                             ExplodedNode *Pred,
00047                                             ExplodedNodeSet &Dst) {
00048   
00049   // ObjCForCollectionStmts are processed in two places.  This method
00050   // handles the case where an ObjCForCollectionStmt* occurs as one of the
00051   // statements within a basic block.  This transfer function does two things:
00052   //
00053   //  (1) binds the next container value to 'element'.  This creates a new
00054   //      node in the ExplodedGraph.
00055   //
00056   //  (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
00057   //      whether or not the container has any more elements.  This value
00058   //      will be tested in ProcessBranch.  We need to explicitly bind
00059   //      this value because a container can contain nil elements.
00060   //
00061   // FIXME: Eventually this logic should actually do dispatches to
00062   //   'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
00063   //   This will require simulating a temporary NSFastEnumerationState, either
00064   //   through an SVal or through the use of MemRegions.  This value can
00065   //   be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
00066   //   terminates we reclaim the temporary (it goes out of scope) and we
00067   //   we can test if the SVal is 0 or if the MemRegion is null (depending
00068   //   on what approach we take).
00069   //
00070   //  For now: simulate (1) by assigning either a symbol or nil if the
00071   //    container is empty.  Thus this transfer function will by default
00072   //    result in state splitting.
00073 
00074   const Stmt *elem = S->getElement();
00075   ProgramStateRef state = Pred->getState();
00076   SVal elementV;
00077   StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
00078   
00079   if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
00080     const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
00081     assert(elemD->getInit() == 0);
00082     elementV = state->getLValue(elemD, Pred->getLocationContext());
00083   }
00084   else {
00085     elementV = state->getSVal(elem, Pred->getLocationContext());
00086   }
00087   
00088   ExplodedNodeSet dstLocation;
00089   Bldr.takeNodes(Pred);
00090   evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
00091   Bldr.addNodes(dstLocation);
00092   
00093   for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
00094        NE = dstLocation.end(); NI!=NE; ++NI) {
00095     Pred = *NI;
00096     ProgramStateRef state = Pred->getState();
00097     const LocationContext *LCtx = Pred->getLocationContext();
00098     
00099     // Handle the case where the container still has elements.
00100     SVal TrueV = svalBuilder.makeTruthVal(1);
00101     ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV);
00102     
00103     // Handle the case where the container has no elements.
00104     SVal FalseV = svalBuilder.makeTruthVal(0);
00105     ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
00106     
00107     if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
00108       if (const TypedValueRegion *R = 
00109           dyn_cast<TypedValueRegion>(MV->getRegion())) {
00110         // FIXME: The proper thing to do is to really iterate over the
00111         //  container.  We will do this with dispatch logic to the store.
00112         //  For now, just 'conjure' up a symbolic value.
00113         QualType T = R->getValueType();
00114         assert(Loc::isLocType(T));
00115         unsigned Count = currentBuilderContext->getCurrentBlockCount();
00116         SymbolRef Sym = SymMgr.getConjuredSymbol(elem, LCtx, T, Count);
00117         SVal V = svalBuilder.makeLoc(Sym);
00118         hasElems = hasElems->bindLoc(elementV, V);
00119         
00120         // Bind the location to 'nil' on the false branch.
00121         SVal nilV = svalBuilder.makeIntVal(0, T);
00122         noElems = noElems->bindLoc(elementV, nilV);
00123       }
00124     
00125     // Create the new nodes.
00126     Bldr.generateNode(S, Pred, hasElems);
00127     Bldr.generateNode(S, Pred, noElems);
00128   }
00129 }
00130 
00131 void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
00132                                   ExplodedNode *Pred,
00133                                   ExplodedNodeSet &Dst) {
00134   
00135   // Handle the previsits checks.
00136   ExplodedNodeSet dstPrevisit;
00137   getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, 
00138                                                    msg, *this);
00139   
00140   // Proceed with evaluate the message expression.
00141   ExplodedNodeSet dstEval;
00142   StmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext);
00143 
00144   for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
00145        DE = dstPrevisit.end(); DI != DE; ++DI) {
00146     
00147     ExplodedNode *Pred = *DI;
00148     bool RaisesException = false;
00149     
00150     if (const Expr *Receiver = msg.getInstanceReceiver()) {
00151       ProgramStateRef state = Pred->getState();
00152       SVal recVal = state->getSVal(Receiver, Pred->getLocationContext());
00153       if (!recVal.isUndef()) {
00154         // Bifurcate the state into nil and non-nil ones.
00155         DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
00156         
00157         ProgramStateRef notNilState, nilState;
00158         llvm::tie(notNilState, nilState) = state->assume(receiverVal);
00159         
00160         // There are three cases: can be nil or non-nil, must be nil, must be
00161         // non-nil. We ignore must be nil, and merge the rest two into non-nil.
00162         if (nilState && !notNilState) {
00163           continue;
00164         }
00165         
00166         // Check if the "raise" message was sent.
00167         assert(notNilState);
00168         if (msg.getSelector() == RaiseSel)
00169           RaisesException = true;
00170         
00171         // If we raise an exception, for now treat it as a sink.
00172         // Eventually we will want to handle exceptions properly.
00173         // Dispatch to plug-in transfer function.
00174         evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException);
00175       }
00176     }
00177     else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
00178       IdentifierInfo* ClsName = Iface->getIdentifier();
00179       Selector S = msg.getSelector();
00180       
00181       // Check for special instance methods.
00182       if (!NSExceptionII) {
00183         ASTContext &Ctx = getContext();
00184         NSExceptionII = &Ctx.Idents.get("NSException");
00185       }
00186       
00187       if (ClsName == NSExceptionII) {
00188         enum { NUM_RAISE_SELECTORS = 2 };
00189         
00190         // Lazily create a cache of the selectors.
00191         if (!NSExceptionInstanceRaiseSelectors) {
00192           ASTContext &Ctx = getContext();
00193           NSExceptionInstanceRaiseSelectors =
00194           new Selector[NUM_RAISE_SELECTORS];
00195           SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
00196           unsigned idx = 0;
00197           
00198           // raise:format:
00199           II.push_back(&Ctx.Idents.get("raise"));
00200           II.push_back(&Ctx.Idents.get("format"));
00201           NSExceptionInstanceRaiseSelectors[idx++] =
00202           Ctx.Selectors.getSelector(II.size(), &II[0]);
00203           
00204           // raise:format::arguments:
00205           II.push_back(&Ctx.Idents.get("arguments"));
00206           NSExceptionInstanceRaiseSelectors[idx++] =
00207           Ctx.Selectors.getSelector(II.size(), &II[0]);
00208         }
00209         
00210         for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
00211           if (S == NSExceptionInstanceRaiseSelectors[i]) {
00212             RaisesException = true;
00213             break;
00214           }
00215       }
00216       
00217       // If we raise an exception, for now treat it as a sink.
00218       // Eventually we will want to handle exceptions properly.
00219       // Dispatch to plug-in transfer function.
00220       evalObjCMessage(Bldr, msg, Pred, Pred->getState(), RaisesException);
00221     }
00222   }
00223   
00224   // Finally, perform the post-condition check of the ObjCMessageExpr and store
00225   // the created nodes in 'Dst'.
00226   getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
00227 }
00228 
00229 void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
00230                                  const ObjCMessage &msg,
00231                                  ExplodedNode *Pred,
00232                                  ProgramStateRef state,
00233                                  bool GenSink) {
00234   // First handle the return value.
00235   SVal ReturnValue = UnknownVal();
00236 
00237   // Some method families have known return values.
00238   switch (msg.getMethodFamily()) {
00239   default:
00240     break;
00241   case OMF_autorelease:
00242   case OMF_retain:
00243   case OMF_self: {
00244     // These methods return their receivers.
00245     const Expr *ReceiverE = msg.getInstanceReceiver();
00246     if (ReceiverE)
00247       ReturnValue = state->getSVal(ReceiverE, Pred->getLocationContext());
00248     break;
00249   }
00250   }
00251 
00252   // If we failed to figure out the return value, use a conjured value instead.
00253   if (ReturnValue.isUnknown()) {
00254     SValBuilder &SVB = getSValBuilder();
00255     QualType ResultTy = msg.getResultType(getContext());
00256     unsigned Count = currentBuilderContext->getCurrentBlockCount();
00257     const Expr *CurrentE = cast<Expr>(currentStmt);
00258     const LocationContext *LCtx = Pred->getLocationContext();
00259     ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy, Count);
00260   }
00261 
00262   // Bind the return value.
00263   const LocationContext *LCtx = Pred->getLocationContext();
00264   state = state->BindExpr(currentStmt, LCtx, ReturnValue);
00265 
00266   // Invalidate the arguments (and the receiver)
00267   state = invalidateArguments(state, CallOrObjCMessage(msg, state, LCtx), LCtx);
00268 
00269   // And create the new node.
00270   Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);
00271   assert(Bldr.hasGeneratedNodes());
00272 }
00273