clang  14.0.0git
ExprEngineObjC.cpp
Go to the documentation of this file.
1 //=-- ExprEngineObjC.cpp - ExprEngine support for Objective-C ---*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines ExprEngine's support for Objective-C expressions.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/AST/StmtObjC.h"
17 
18 using namespace clang;
19 using namespace ento;
20 
22  ExplodedNode *Pred,
23  ExplodedNodeSet &Dst) {
24  ProgramStateRef state = Pred->getState();
25  const LocationContext *LCtx = Pred->getLocationContext();
26  SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
27  SVal location = state->getLValue(Ex->getDecl(), baseVal);
28 
29  ExplodedNodeSet dstIvar;
30  StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx);
31  Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
32 
33  // Perform the post-condition check of the ObjCIvarRefExpr and store
34  // the created nodes in 'Dst'.
35  getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
36 }
37 
39  ExplodedNode *Pred,
40  ExplodedNodeSet &Dst) {
41  getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
42 }
43 
44 /// Generate a node in \p Bldr for an iteration statement using ObjC
45 /// for-loop iterator.
47  ExplodedNodeSet &dstLocation, SValBuilder &svalBuilder,
48  const ObjCForCollectionStmt *S, const Stmt *elem, SVal elementV,
49  SymbolManager &SymMgr, const NodeBuilderContext *currBldrCtx,
50  StmtNodeBuilder &Bldr, bool hasElements) {
51 
52  for (ExplodedNode *Pred : dstLocation) {
53  ProgramStateRef state = Pred->getState();
54  const LocationContext *LCtx = Pred->getLocationContext();
55 
56  ProgramStateRef nextState =
57  ExprEngine::setWhetherHasMoreIteration(state, S, LCtx, hasElements);
58 
59  if (auto MV = elementV.getAs<loc::MemRegionVal>())
60  if (const auto *R = dyn_cast<TypedValueRegion>(MV->getRegion())) {
61  // FIXME: The proper thing to do is to really iterate over the
62  // container. We will do this with dispatch logic to the store.
63  // For now, just 'conjure' up a symbolic value.
64  QualType T = R->getValueType();
65  assert(Loc::isLocType(T));
66 
67  SVal V;
68  if (hasElements) {
69  SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
70  currBldrCtx->blockCount());
71  V = svalBuilder.makeLoc(Sym);
72  } else {
73  V = svalBuilder.makeIntVal(0, T);
74  }
75 
76  nextState = nextState->bindLoc(elementV, V, LCtx);
77  }
78 
79  Bldr.generateNode(S, Pred, nextState);
80  }
81 }
82 
84  ExplodedNode *Pred,
85  ExplodedNodeSet &Dst) {
86 
87  // ObjCForCollectionStmts are processed in two places. This method
88  // handles the case where an ObjCForCollectionStmt* occurs as one of the
89  // statements within a basic block. This transfer function does two things:
90  //
91  // (1) binds the next container value to 'element'. This creates a new
92  // node in the ExplodedGraph.
93  //
94  // (2) note whether the collection has any more elements (or in other words,
95  // whether the loop has more iterations). This will be tested in
96  // processBranch.
97  //
98  // FIXME: Eventually this logic should actually do dispatches to
99  // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
100  // This will require simulating a temporary NSFastEnumerationState, either
101  // through an SVal or through the use of MemRegions. This value can
102  // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
103  // terminates we reclaim the temporary (it goes out of scope) and we
104  // we can test if the SVal is 0 or if the MemRegion is null (depending
105  // on what approach we take).
106  //
107  // For now: simulate (1) by assigning either a symbol or nil if the
108  // container is empty. Thus this transfer function will by default
109  // result in state splitting.
110 
111  const Stmt *elem = S->getElement();
112  const Stmt *collection = S->getCollection();
113  ProgramStateRef state = Pred->getState();
114  SVal collectionV = state->getSVal(collection, Pred->getLocationContext());
115 
116  SVal elementV;
117  if (const auto *DS = dyn_cast<DeclStmt>(elem)) {
118  const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
119  assert(elemD->getInit() == nullptr);
120  elementV = state->getLValue(elemD, Pred->getLocationContext());
121  } else {
122  elementV = state->getSVal(elem, Pred->getLocationContext());
123  }
124 
125  bool isContainerNull = state->isNull(collectionV).isConstrainedTrue();
126 
127  ExplodedNodeSet dstLocation;
128  evalLocation(dstLocation, S, elem, Pred, state, elementV, false);
129 
130  ExplodedNodeSet Tmp;
131  StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
132 
133  if (!isContainerNull)
134  populateObjCForDestinationSet(dstLocation, svalBuilder, S, elem, elementV,
135  SymMgr, currBldrCtx, Bldr,
136  /*hasElements=*/true);
137 
138  populateObjCForDestinationSet(dstLocation, svalBuilder, S, elem, elementV,
139  SymMgr, currBldrCtx, Bldr,
140  /*hasElements=*/false);
141 
142  // Finally, run any custom checkers.
143  // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
144  getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
145 }
146 
148  ExplodedNode *Pred,
149  ExplodedNodeSet &Dst) {
152  CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
153 
154  // There are three cases for the receiver:
155  // (1) it is definitely nil,
156  // (2) it is definitely non-nil, and
157  // (3) we don't know.
158  //
159  // If the receiver is definitely nil, we skip the pre/post callbacks and
160  // instead call the ObjCMessageNil callbacks and return.
161  //
162  // If the receiver is definitely non-nil, we call the pre- callbacks,
163  // evaluate the call, and call the post- callbacks.
164  //
165  // If we don't know, we drop the potential nil flow and instead
166  // continue from the assumed non-nil state as in (2). This approach
167  // intentionally drops coverage in order to prevent false alarms
168  // in the following scenario:
169  //
170  // id result = [o someMethod]
171  // if (result) {
172  // if (!o) {
173  // // <-- This program point should be unreachable because if o is nil
174  // // it must the case that result is nil as well.
175  // }
176  // }
177  //
178  // We could avoid dropping coverage by performing an explicit case split
179  // on each method call -- but this would get very expensive. An alternative
180  // would be to introduce lazy constraints.
181  // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
182  // Revisit once we have lazier constraints.
183  if (Msg->isInstanceMessage()) {
184  SVal recVal = Msg->getReceiverSVal();
185  if (!recVal.isUndef()) {
186  // Bifurcate the state into nil and non-nil ones.
187  DefinedOrUnknownSVal receiverVal =
188  recVal.castAs<DefinedOrUnknownSVal>();
189  ProgramStateRef State = Pred->getState();
190 
191  ProgramStateRef notNilState, nilState;
192  std::tie(notNilState, nilState) = State->assume(receiverVal);
193 
194  // Receiver is definitely nil, so run ObjCMessageNil callbacks and return.
195  if (nilState && !notNilState) {
196  ExplodedNodeSet dstNil;
197  StmtNodeBuilder Bldr(Pred, dstNil, *currBldrCtx);
198  bool HasTag = Pred->getLocation().getTag();
199  Pred = Bldr.generateNode(ME, Pred, nilState, nullptr,
201  assert((Pred || HasTag) && "Should have cached out already!");
202  (void)HasTag;
203  if (!Pred)
204  return;
205 
206  ExplodedNodeSet dstPostCheckers;
207  getCheckerManager().runCheckersForObjCMessageNil(dstPostCheckers, Pred,
208  *Msg, *this);
209  for (auto I : dstPostCheckers)
210  finishArgumentConstruction(Dst, I, *Msg);
211  return;
212  }
213 
214  ExplodedNodeSet dstNonNil;
215  StmtNodeBuilder Bldr(Pred, dstNonNil, *currBldrCtx);
216  // Generate a transition to the non-nil state, dropping any potential
217  // nil flow.
218  if (notNilState != State) {
219  bool HasTag = Pred->getLocation().getTag();
220  Pred = Bldr.generateNode(ME, Pred, notNilState);
221  assert((Pred || HasTag) && "Should have cached out already!");
222  (void)HasTag;
223  if (!Pred)
224  return;
225  }
226  }
227  }
228 
229  // Handle the previsits checks.
230  ExplodedNodeSet dstPrevisit;
232  *Msg, *this);
233  ExplodedNodeSet dstGenericPrevisit;
234  getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
235  *Msg, *this);
236 
237  // Proceed with evaluate the message expression.
238  ExplodedNodeSet dstEval;
239  StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
240 
241  for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
242  DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
243  ExplodedNode *Pred = *DI;
244  ProgramStateRef State = Pred->getState();
246 
247  if (UpdatedMsg->isInstanceMessage()) {
248  SVal recVal = UpdatedMsg->getReceiverSVal();
249  if (!recVal.isUndef()) {
250  if (ObjCNoRet.isImplicitNoReturn(ME)) {
251  // If we raise an exception, for now treat it as a sink.
252  // Eventually we will want to handle exceptions properly.
253  Bldr.generateSink(ME, Pred, State);
254  continue;
255  }
256  }
257  } else {
258  // Check for special class methods that are known to not return
259  // and that we should treat as a sink.
260  if (ObjCNoRet.isImplicitNoReturn(ME)) {
261  // If we raise an exception, for now treat it as a sink.
262  // Eventually we will want to handle exceptions properly.
263  Bldr.generateSink(ME, Pred, Pred->getState());
264  continue;
265  }
266  }
267 
268  defaultEvalCall(Bldr, Pred, *UpdatedMsg);
269  }
270 
271  // If there were constructors called for object-type arguments, clean them up.
272  ExplodedNodeSet dstArgCleanup;
273  for (auto I : dstEval)
274  finishArgumentConstruction(dstArgCleanup, I, *Msg);
275 
276  ExplodedNodeSet dstPostvisit;
277  getCheckerManager().runCheckersForPostCall(dstPostvisit, dstArgCleanup,
278  *Msg, *this);
279 
280  // Finally, perform the post-condition check of the ObjCMessageExpr and store
281  // the created nodes in 'Dst'.
283  *Msg, *this);
284 }
clang::ento::CheckerManager::runCheckersForObjCMessageNil
void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng)
Run checkers for visiting an obj-c message to nil.
Definition: CheckerManager.h:295
clang::ento::StmtNodeBuilder::generateSink
ExplodedNode * generateSink(const Stmt *S, ExplodedNode *Pred, ProgramStateRef St, const ProgramPointTag *tag=nullptr, ProgramPoint::Kind K=ProgramPoint::PostStmtKind)
Definition: CoreEngine.h:418
clang::ento::Loc::isLocType
static bool isLocType(QualType T)
Definition: SVals.h:336
clang::ento::ExprEngine::getStateManager
ProgramStateManager & getStateManager()
Definition: ExprEngine.h:415
clang::ento::ExplodedNode::getLocationContext
const LocationContext * getLocationContext() const
Definition: ExplodedGraph.h:146
clang::ento::CallEventRef
Definition: CallEvent.h:82
clang::LocationContext
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Definition: AnalysisDeclContext.h:215
clang::ento::CheckerManager::runCheckersForPreObjCMessage
void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng)
Run checkers for pre-visiting obj-c messages.
Definition: CheckerManager.h:277
clang::ento::SVal::castAs
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:103
clang::ento::SVal::isUndef
bool isUndef() const
Definition: SVals.h:140
clang::ento::ExplodedNodeSet::iterator
ImplTy::iterator iterator
Definition: ExplodedGraph.h:479
clang::ento::DefinedOrUnknownSVal
Definition: SVals.h:236
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
clang::ento::CallEventManager::getObjCMethodCall
CallEventRef< ObjCMethodCall > getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, const LocationContext *LCtx)
Definition: CallEvent.h:1408
clang::ento::ExplodedNode
Definition: ExplodedGraph.h:65
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:110
clang::ento::ExprEngine::VisitLvalObjCIvarRefExpr
void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred, ExplodedNodeSet &Dst)
Transfer function logic for computing the lvalue of an Objective-C ivar.
Definition: ExprEngineObjC.cpp:21
clang::ento::CheckerManager::runCheckersForPostCall
void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng, bool wasInlined=false)
Run checkers for post-visiting obj-c messages.
Definition: CheckerManager.h:317
clang::ento::StmtNodeBuilder
Definition: CoreEngine.h:379
clang::ObjCForCollectionStmt
Represents Objective-C's collection statement.
Definition: StmtObjC.h:23
CallEvent.h
clang::ObjCIvarRefExpr::getDecl
ObjCIvarDecl * getDecl()
Definition: ExprObjC.h:576
V
#define V(N, I)
Definition: ASTContext.h:3121
clang::ento::ExplodedNode::getState
const ProgramStateRef & getState() const
Definition: ExplodedGraph.h:169
CheckerManager.h
clang::ProgramPoint::getTag
const ProgramPointTag * getTag() const
Definition: ProgramPoint.h:177
clang::ObjCAtSynchronizedStmt
Represents Objective-C's @synchronized statement.
Definition: StmtObjC.h:277
clang::ento::ExplodedNodeSet::end
iterator end()
Definition: ExplodedGraph.h:497
populateObjCForDestinationSet
static void populateObjCForDestinationSet(ExplodedNodeSet &dstLocation, SValBuilder &svalBuilder, const ObjCForCollectionStmt *S, const Stmt *elem, SVal elementV, SymbolManager &SymMgr, const NodeBuilderContext *currBldrCtx, StmtNodeBuilder &Bldr, bool hasElements)
Generate a node in Bldr for an iteration statement using ObjC for-loop iterator.
Definition: ExprEngineObjC.cpp:46
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:876
clang::ento::ExprEngine::VisitObjCForCollectionStmt
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst)
VisitObjCForCollectionStmt - Transfer function logic for ObjCForCollectionStmt.
Definition: ExprEngineObjC.cpp:83
clang::ento::CheckerManager::runCheckersForPreCall
void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng)
Run checkers for pre-visiting obj-c messages.
Definition: CheckerManager.h:311
clang::ObjCMessageExpr
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:940
StmtObjC.h
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
clang::ento::CallEventManager
Manages the lifetime of CallEvent objects.
Definition: CallEvent.h:1339
clang::ento::ProgramStateManager::getCallEventManager
CallEventManager & getCallEventManager()
Definition: ProgramState.h:537
clang::ProgramPoint::PreStmtKind
@ PreStmtKind
Definition: ProgramPoint.h:64
clang::ento::CheckerManager::runCheckersForPostStmt
void runCheckersForPostStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng, bool wasInlined=false)
Run checkers for post-visiting Stmts.
Definition: CheckerManager.h:262
State
LineState State
Definition: UnwrappedLineFormatter.cpp:986
clang::VarDecl::getInit
const Expr * getInit() const
Definition: Decl.h:1285
clang::ObjCNoReturn::isImplicitNoReturn
bool isImplicitNoReturn(const ObjCMessageExpr *ME)
Return true if the given message expression is known to never return.
Definition: ObjCNoReturn.cpp:48
clang::ento::ExplodedNodeSet::begin
iterator begin()
Definition: ExplodedGraph.h:496
clang::ento::ExprEngine::setWhetherHasMoreIteration
static LLVM_NODISCARD ProgramStateRef setWhetherHasMoreIteration(ProgramStateRef State, const ObjCForCollectionStmt *O, const LocationContext *LC, bool HasMoreIteraton)
Note whether this loop has any more iteratios to model.
Definition: ExprEngine.cpp:2144
ExprEngine.h
clang::ento::CheckerManager::runCheckersForPostObjCMessage
void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng, bool wasInlined=false)
Run checkers for post-visiting obj-c messages.
Definition: CheckerManager.h:285
clang
Definition: CalledOnceCheck.h:17
clang::ento::ExprEngine::VisitObjCAtSynchronizedStmt
void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst)
Transfer function logic for ObjCAtSynchronizedStmts.
Definition: ExprEngineObjC.cpp:38
clang::ento::ExplodedNode::getLocation
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
Definition: ExplodedGraph.h:144
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:69
clang::ento::CallEventRef::cloneWithState
CallEventRef< T > cloneWithState(ProgramStateRef State) const
Definition: CallEvent.h:87
clang::ento::SVal
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:75
clang::ObjCIvarRefExpr::getBase
const Expr * getBase() const
Definition: ExprObjC.h:580
clang::ento::CheckerManager::runCheckersForPreStmt
void runCheckersForPreStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng)
Run checkers for pre-visiting Stmts.
Definition: CheckerManager.h:249
clang::ento::StmtNodeBuilder::generateNode
ExplodedNode * generateNode(const Stmt *S, ExplodedNode *Pred, ProgramStateRef St, const ProgramPointTag *tag=nullptr, ProgramPoint::Kind K=ProgramPoint::PostStmtKind)
Definition: CoreEngine.h:408
clang::ento::ExplodedNodeSet
Definition: ExplodedGraph.h:463
clang::ObjCIvarRefExpr
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition: ExprObjC.h:548
clang::ento::ExprEngine::defaultEvalCall
void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, const CallEvent &Call, const EvalCallOptions &CallOpts={})
Default implementation of call evaluation.
Definition: ExprEngineCallAndReturn.cpp:1047
llvm::IntrusiveRefCntPtr< const ProgramState >
clang::ento::ExprEngine::VisitObjCMessage
void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst)
Definition: ExprEngineObjC.cpp:147
clang::ento::ExprEngine::getCheckerManager
CheckerManager & getCheckerManager() const
Definition: ExprEngine.h:214