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/CallEvent.h"
00017 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.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, *currBldrCtx);
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   
00078   if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
00079     const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
00080     assert(elemD->getInit() == nullptr);
00081     elementV = state->getLValue(elemD, Pred->getLocationContext());
00082   }
00083   else {
00084     elementV = state->getSVal(elem, Pred->getLocationContext());
00085   }
00086   
00087   ExplodedNodeSet dstLocation;
00088   evalLocation(dstLocation, S, elem, Pred, state, elementV, nullptr, false);
00089 
00090   ExplodedNodeSet Tmp;
00091   StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
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 (Optional<loc::MemRegionVal> MV = elementV.getAs<loc::MemRegionVal>())
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         SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
00116                                              currBldrCtx->blockCount());
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   // Finally, run any custom checkers.
00131   // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
00132   getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
00133 }
00134 
00135 void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
00136                                   ExplodedNode *Pred,
00137                                   ExplodedNodeSet &Dst) {
00138   CallEventManager &CEMgr = getStateManager().getCallEventManager();
00139   CallEventRef<ObjCMethodCall> Msg =
00140     CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
00141 
00142   // Handle the previsits checks.
00143   ExplodedNodeSet dstPrevisit;
00144   getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
00145                                                    *Msg, *this);
00146   ExplodedNodeSet dstGenericPrevisit;
00147   getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
00148                                             *Msg, *this);
00149 
00150   // Proceed with evaluate the message expression.
00151   ExplodedNodeSet dstEval;
00152   StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
00153 
00154   for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
00155        DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
00156     ExplodedNode *Pred = *DI;
00157     ProgramStateRef State = Pred->getState();
00158     CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
00159     
00160     if (UpdatedMsg->isInstanceMessage()) {
00161       SVal recVal = UpdatedMsg->getReceiverSVal();
00162       if (!recVal.isUndef()) {
00163         // Bifurcate the state into nil and non-nil ones.
00164         DefinedOrUnknownSVal receiverVal =
00165             recVal.castAs<DefinedOrUnknownSVal>();
00166 
00167         ProgramStateRef notNilState, nilState;
00168         std::tie(notNilState, nilState) = State->assume(receiverVal);
00169         
00170         // There are three cases: can be nil or non-nil, must be nil, must be
00171         // non-nil. We ignore must be nil, and merge the rest two into non-nil.
00172         // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
00173         // Revisit once we have lazier constraints.
00174         if (nilState && !notNilState) {
00175           continue;
00176         }
00177         
00178         // Check if the "raise" message was sent.
00179         assert(notNilState);
00180         if (ObjCNoRet.isImplicitNoReturn(ME)) {
00181           // If we raise an exception, for now treat it as a sink.
00182           // Eventually we will want to handle exceptions properly.
00183           Bldr.generateSink(ME, Pred, State);
00184           continue;
00185         }
00186         
00187         // Generate a transition to non-Nil state.
00188         if (notNilState != State) {
00189           Pred = Bldr.generateNode(ME, Pred, notNilState);
00190           assert(Pred && "Should have cached out already!");
00191         }
00192       }
00193     } else {
00194       // Check for special class methods that are known to not return
00195       // and that we should treat as a sink.
00196       if (ObjCNoRet.isImplicitNoReturn(ME)) {
00197         // If we raise an exception, for now treat it as a sink.
00198         // Eventually we will want to handle exceptions properly.
00199         Bldr.generateSink(ME, Pred, Pred->getState());
00200         continue;
00201       }
00202     }
00203 
00204     defaultEvalCall(Bldr, Pred, *UpdatedMsg);
00205   }
00206   
00207   ExplodedNodeSet dstPostvisit;
00208   getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
00209                                              *Msg, *this);
00210 
00211   // Finally, perform the post-condition check of the ObjCMessageExpr and store
00212   // the created nodes in 'Dst'.
00213   getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
00214                                                     *Msg, *this);
00215 }