clang 10.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"
14 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
15 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
17
18 using namespace clang;
19 using namespace ento;
20
21 void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
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
38 void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
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.
46 static void populateObjCForDestinationSet(
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 SVal hasElementsV = svalBuilder.makeTruthVal(hasElements);
57
58 // FIXME: S is not an expression. We should not be binding values to it.
59 ProgramStateRef nextState = state->BindExpr(S, LCtx, hasElementsV);
60
61 if (auto MV = elementV.getAs<loc::MemRegionVal>())
62 if (const auto *R = dyn_cast<TypedValueRegion>(MV->getRegion())) {
63 // FIXME: The proper thing to do is to really iterate over the
64 // container. We will do this with dispatch logic to the store.
65 // For now, just 'conjure' up a symbolic value.
66 QualType T = R->getValueType();
67 assert(Loc::isLocType(T));
68
69 SVal V;
70 if (hasElements) {
71 SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
72 currBldrCtx->blockCount());
73 V = svalBuilder.makeLoc(Sym);
74 } else {
75 V = svalBuilder.makeIntVal(0, T);
76 }
77
78 nextState = nextState->bindLoc(elementV, V, LCtx);
79 }
80
81 Bldr.generateNode(S, Pred, nextState);
82 }
83 }
84
85 void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
86 ExplodedNode *Pred,
87 ExplodedNodeSet &Dst) {
88
89 // ObjCForCollectionStmts are processed in two places. This method
90 // handles the case where an ObjCForCollectionStmt* occurs as one of the
91 // statements within a basic block. This transfer function does two things:
92 //
93 // (1) binds the next container value to 'element'. This creates a new
94 // node in the ExplodedGraph.
95 //
96 // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
97 // whether or not the container has any more elements. This value
98 // will be tested in ProcessBranch. We need to explicitly bind
99 // this value because a container can contain nil elements.
100 //
101 // FIXME: Eventually this logic should actually do dispatches to
102 // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
103 // This will require simulating a temporary NSFastEnumerationState, either
104 // through an SVal or through the use of MemRegions. This value can
105 // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
106 // terminates we reclaim the temporary (it goes out of scope) and we
107 // we can test if the SVal is 0 or if the MemRegion is null (depending
108 // on what approach we take).
109 //
110 // For now: simulate (1) by assigning either a symbol or nil if the
111 // container is empty. Thus this transfer function will by default
112 // result in state splitting.
113
114 const Stmt *elem = S->getElement();
115 const Stmt *collection = S->getCollection();
116 ProgramStateRef state = Pred->getState();
117 SVal collectionV = state->getSVal(collection, Pred->getLocationContext());
118
119 SVal elementV;
120 if (const auto *DS = dyn_cast<DeclStmt>(elem)) {
121 const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
122 assert(elemD->getInit() == nullptr);
123 elementV = state->getLValue(elemD, Pred->getLocationContext());
124 } else {
125 elementV = state->getSVal(elem, Pred->getLocationContext());
126 }
127
128 bool isContainerNull = state->isNull(collectionV).isConstrainedTrue();
129
130 ExplodedNodeSet dstLocation;
131 evalLocation(dstLocation, S, elem, Pred, state, elementV, false);
132
133 ExplodedNodeSet Tmp;
134 StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
135
136 if (!isContainerNull)
137 populateObjCForDestinationSet(dstLocation, svalBuilder, S, elem, elementV,
138 SymMgr, currBldrCtx, Bldr,
139 /*hasElements=*/true);
140
141 populateObjCForDestinationSet(dstLocation, svalBuilder, S, elem, elementV,
142 SymMgr, currBldrCtx, Bldr,
143 /*hasElements=*/false);
144
145 // Finally, run any custom checkers.
146 // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
147 getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
148 }
149
150 void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
151 ExplodedNode *Pred,
152 ExplodedNodeSet &Dst) {
153 CallEventManager &CEMgr = getStateManager().getCallEventManager();
154 CallEventRef<ObjCMethodCall> Msg =
155 CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
156
157 // There are three cases for the receiver:
158 // (1) it is definitely nil,
159 // (2) it is definitely non-nil, and
160 // (3) we don't know.
161 //
162 // If the receiver is definitely nil, we skip the pre/post callbacks and
163 // instead call the ObjCMessageNil callbacks and return.
164 //
165 // If the receiver is definitely non-nil, we call the pre- callbacks,
166 // evaluate the call, and call the post- callbacks.
167 //
168 // If we don't know, we drop the potential nil flow and instead
169 // continue from the assumed non-nil state as in (2). This approach
170 // intentionally drops coverage in order to prevent false alarms
171 // in the following scenario:
172 //
173 // id result = [o someMethod]
174 // if (result) {
175 // if (!o) {
176 // // <-- This program point should be unreachable because if o is nil
177 // // it must the case that result is nil as well.
178 // }
179 // }
180 //
181 // We could avoid dropping coverage by performing an explicit case split
182 // on each method call -- but this would get very expensive. An alternative
183 // would be to introduce lazy constraints.
184 // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
185 // Revisit once we have lazier constraints.
186 if (Msg->isInstanceMessage()) {
187 SVal recVal = Msg->getReceiverSVal();
188 if (!recVal.isUndef()) {
189 // Bifurcate the state into nil and non-nil ones.
190 DefinedOrUnknownSVal receiverVal =
191 recVal.castAs<DefinedOrUnknownSVal>();
192 ProgramStateRef State = Pred->getState();
193
194 ProgramStateRef notNilState, nilState;
195 std::tie(notNilState, nilState) = State->assume(receiverVal);
196
197 // Receiver is definitely nil, so run ObjCMessageNil callbacks and return.
198 if (nilState && !notNilState) {
199 ExplodedNodeSet dstNil;
200 StmtNodeBuilder Bldr(Pred, dstNil, *currBldrCtx);
201 bool HasTag = Pred->getLocation().getTag();
202 Pred = Bldr.generateNode(ME, Pred, nilState, nullptr,
203 ProgramPoint::PreStmtKind);
204 assert((Pred || HasTag) && "Should have cached out already!");
205 (void)HasTag;
206 if (!Pred)
207 return;
208
209 ExplodedNodeSet dstPostCheckers;
210 getCheckerManager().runCheckersForObjCMessageNil(dstPostCheckers, Pred,
211 *Msg, *this);
212 for (auto I : dstPostCheckers)
213 finishArgumentConstruction(Dst, I, *Msg);
214 return;
215 }
216
217 ExplodedNodeSet dstNonNil;
218 StmtNodeBuilder Bldr(Pred, dstNonNil, *currBldrCtx);
219 // Generate a transition to the non-nil state, dropping any potential
220 // nil flow.
221 if (notNilState != State) {
222 bool HasTag = Pred->getLocation().getTag();
223 Pred = Bldr.generateNode(ME, Pred, notNilState);
224 assert((Pred || HasTag) && "Should have cached out already!");
225 (void)HasTag;
226 if (!Pred)
227 return;
228 }
229 }
230 }
231
232 // Handle the previsits checks.
233 ExplodedNodeSet dstPrevisit;
234 getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
235 *Msg, *this);
236 ExplodedNodeSet dstGenericPrevisit;
237 getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
238 *Msg, *this);
239
240 // Proceed with evaluate the message expression.
241 ExplodedNodeSet dstEval;
242 StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
243
244 for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
245 DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
246 ExplodedNode *Pred = *DI;
247 ProgramStateRef State = Pred->getState();
248 CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
249
250 if (UpdatedMsg->isInstanceMessage()) {
251 SVal recVal = UpdatedMsg->getReceiverSVal();
252 if (!recVal.isUndef()) {
253 if (ObjCNoRet.isImplicitNoReturn(ME)) {
254 // If we raise an exception, for now treat it as a sink.
255 // Eventually we will want to handle exceptions properly.
256 Bldr.generateSink(ME, Pred, State);
257 continue;
258 }
259 }
260 } else {
261 // Check for special class methods that are known to not return
262 // and that we should treat as a sink.
263 if (ObjCNoRet.isImplicitNoReturn(ME)) {
264 // If we raise an exception, for now treat it as a sink.
265 // Eventually we will want to handle exceptions properly.
266 Bldr.generateSink(ME, Pred, Pred->getState());
267 continue;
268 }
269 }
270
271 defaultEvalCall(Bldr, Pred, *UpdatedMsg);
272 }
273
274 // If there were constructors called for object-type arguments, clean them up.
275 ExplodedNodeSet dstArgCleanup;
276 for (auto I : dstEval)
277 finishArgumentConstruction(dstArgCleanup, I, *Msg);
278
279 ExplodedNodeSet dstPostvisit;
280 getCheckerManager().runCheckersForPostCall(dstPostvisit, dstArgCleanup,
281 *Msg, *this);
282
283 // Finally, perform the post-condition check of the ObjCMessageExpr and store
284 // the created nodes in 'Dst'.
285 getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
286 *Msg, *this);
287 }
ento
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:654
clang::ento::ExplodedNodeSet::iterator
ImplTy::iterator iterator
Definition: ExplodedGraph.h:479
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:66
clang::ento::StmtNodeBuilder
This builder class is useful for generating nodes that resulted from visiting a statement.
Definition: CoreEngine.h:378
clang::CallEventManager
Manages the lifetime of CallEvent objects.
Definition: CallEvent.h:1148
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
clang::ObjCForCollectionStmt::getCollection
Expr * getCollection()
Definition: StmtObjC.h:35
clang::LocationContext
Definition: AnalysisDeclContext.h:216
clang::ento::ExplodedNode::getState
const ProgramStateRef & getState() const
Definition: ExplodedGraph.h:169
clang::ento::ExplodedNodeSet::end
iterator end()
Definition: ExplodedGraph.h:497
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:820
StmtObjC.h
Defines the Objective-C statement AST node classes.
clang::ProgramPoint::PreStmtKind
Definition: ProgramPoint.h:64
ExprEngine.h
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:110
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:256
State
LineState State
Definition: UnwrappedLineFormatter.cpp:932
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
CheckerManager.h
clang::ento::ExplodedNode
Definition: ExplodedGraph.h:65
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:246
clang::CodeGen::state
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
Definition: CGOpenMPRuntime.h:802
clang::ento::Loc::isLocType
static bool isLocType(QualType T)
Definition: SVals.h:329
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:417
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:272
clang::ento::ExplodedNode::getLocationContext
const LocationContext * getLocationContext() const
Definition: ExplodedGraph.h:146
clang::ento::DefinedOrUnknownSVal
Definition: SVals.h:229
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:278
clang::ObjCIvarRefExpr::getDecl
ObjCIvarDecl * getDecl()
Definition: ExprObjC.h:576
clang::ento::ExprEngine::getCheckerManager
CheckerManager & getCheckerManager() const
Definition: ExprEngine.h:190
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:223
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
V
#define V(N, I)
Definition: ASTContext.h:2941
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:238
clang::ObjCAtSynchronizedStmt
Represents Objective-C&#39;s @synchronized statement.
Definition: StmtObjC.h:277
clang::ObjCMessageExpr
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:950
clang::CallEventManager::getObjCMethodCall
CallEventRef< ObjCMethodCall > getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, const LocationContext *LCtx)
Definition: CallEvent.h:1217
llvm::IntrusiveRefCntPtr< const ProgramState >
clang::ento::ExplodedNodeSet
Definition: ExplodedGraph.h:463
clang::ento::ProgramStateManager::getCallEventManager
CallEventManager & getCallEventManager()
Definition: ProgramState.h:530
clang::ento::ExplodedNode::getLocation
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
Definition: ExplodedGraph.h:144
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::ento::ExprEngine::VisitObjCForCollectionStmt
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst)
VisitObjCForCollectionStmt - Transfer function logic for ObjCForCollectionStmt.
Definition: ExprEngineObjC.cpp:85
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:210
clang::ObjCForCollectionStmt::getElement
Stmt * getElement()
Definition: StmtObjC.h:34
clang::ento::CallEventRef
Definition: CallEvent.h:77
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
clang::ento::ExplodedNodeSet::begin
iterator begin()
Definition: ExplodedGraph.h:496
clang::VarDecl::getInit
const Expr * getInit() const
Definition: Decl.h:1229
clang::ProgramPoint::getTag
const ProgramPointTag * getTag() const
Definition: ProgramPoint.h:177
clang::ento::ExprEngine::getStateManager
ProgramStateManager & getStateManager() override
Definition: ExprEngine.h:384
clang::ento::ExprEngine::defaultEvalCall
void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, const CallEvent &Call, const EvalCallOptions &CallOpts={})
Default implementation of call evaluation.
Definition: ExprEngineCallAndReturn.cpp:1038
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::ObjCNoReturn::isImplicitNoReturn
bool isImplicitNoReturn(const ObjCMessageExpr *ME)
Return true if the given message expression is known to never return.
Definition: ObjCNoReturn.cpp:48
clang::ObjCForCollectionStmt
Represents Objective-C&#39;s collection statement.
Definition: StmtObjC.h:23
clang::ento::ExprEngine::VisitObjCAtSynchronizedStmt
void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst)
Transfer function logic for ObjCAtSynchronizedStmts.
Definition: ExprEngineObjC.cpp:38
clang::ento::ExprEngine::VisitObjCMessage
void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst)
Definition: ExprEngineObjC.cpp:150
clang::ObjCIvarRefExpr::getBase
const Expr * getBase() const
Definition: ExprObjC.h:580
clang::ObjCIvarRefExpr
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition: ExprObjC.h:546
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:407
clang::ento::SVal::isUndef
bool isUndef() const
Definition: SVals.h:140
CallEvent.h
clang::ento::CallEventRef::cloneWithState
CallEventRef< T > cloneWithState(ProgramStateRef State) const
Definition: CallEvent.h:82