blob: 4b8d7bd262ac0ab549a81116d7cb73d253f87538 [file] [log] [blame]
George Karpenkov70c2ee32018-08-17 21:41:07 +00001//==-- RetainCountChecker.cpp - Checks for leaks and other issues -*- C++ -*--//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
George Karpenkov70c2ee32018-08-17 21:41:07 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the methods for RetainCountChecker, which implements
10// a reference count checker for Core Foundation and Cocoa on (Mac OS X).
11//
12//===----------------------------------------------------------------------===//
13
14#include "RetainCountChecker.h"
15
16using namespace clang;
17using namespace ento;
George Karpenkov70c2ee32018-08-17 21:41:07 +000018using namespace retaincountchecker;
19using llvm::StrInStrNoCase;
20
21REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
22
23namespace clang {
24namespace ento {
25namespace retaincountchecker {
26
27const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) {
28 return State->get<RefBindings>(Sym);
29}
30
George Karpenkov2c2d0b62019-01-18 19:24:55 +000031} // end namespace retaincountchecker
32} // end namespace ento
33} // end namespace clang
34
George Karpenkovf153cdf2019-01-16 23:21:15 +000035static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym,
George Karpenkov70c2ee32018-08-17 21:41:07 +000036 RefVal Val) {
George Karpenkovd5ef0d22018-08-29 20:28:33 +000037 assert(Sym != nullptr);
George Karpenkov70c2ee32018-08-17 21:41:07 +000038 return State->set<RefBindings>(Sym, Val);
39}
40
George Karpenkovf153cdf2019-01-16 23:21:15 +000041static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) {
George Karpenkov70c2ee32018-08-17 21:41:07 +000042 return State->remove<RefBindings>(Sym);
43}
44
George Karpenkov70c2ee32018-08-17 21:41:07 +000045void RefVal::print(raw_ostream &Out) const {
46 if (!T.isNull())
George Karpenkov081c4772018-10-23 23:11:50 +000047 Out << "Tracked " << T.getAsString() << " | ";
George Karpenkov70c2ee32018-08-17 21:41:07 +000048
49 switch (getKind()) {
50 default: llvm_unreachable("Invalid RefVal kind");
51 case Owned: {
52 Out << "Owned";
53 unsigned cnt = getCount();
54 if (cnt) Out << " (+ " << cnt << ")";
55 break;
56 }
57
58 case NotOwned: {
59 Out << "NotOwned";
60 unsigned cnt = getCount();
61 if (cnt) Out << " (+ " << cnt << ")";
62 break;
63 }
64
65 case ReturnedOwned: {
66 Out << "ReturnedOwned";
67 unsigned cnt = getCount();
68 if (cnt) Out << " (+ " << cnt << ")";
69 break;
70 }
71
72 case ReturnedNotOwned: {
73 Out << "ReturnedNotOwned";
74 unsigned cnt = getCount();
75 if (cnt) Out << " (+ " << cnt << ")";
76 break;
77 }
78
79 case Released:
80 Out << "Released";
81 break;
82
83 case ErrorDeallocNotOwned:
84 Out << "-dealloc (not-owned)";
85 break;
86
87 case ErrorLeak:
88 Out << "Leaked";
89 break;
90
91 case ErrorLeakReturned:
92 Out << "Leaked (Bad naming)";
93 break;
94
95 case ErrorUseAfterRelease:
96 Out << "Use-After-Release [ERROR]";
97 break;
98
99 case ErrorReleaseNotOwned:
100 Out << "Release of Not-Owned [ERROR]";
101 break;
102
103 case RefVal::ErrorOverAutorelease:
104 Out << "Over-autoreleased";
105 break;
106
107 case RefVal::ErrorReturnedNotOwned:
108 Out << "Non-owned object returned instead of owned";
109 break;
110 }
111
112 switch (getIvarAccessHistory()) {
113 case IvarAccessHistory::None:
114 break;
115 case IvarAccessHistory::AccessedDirectly:
116 Out << " [direct ivar access]";
117 break;
118 case IvarAccessHistory::ReleasedAfterDirectAccess:
119 Out << " [released after direct ivar access]";
120 }
121
122 if (ACnt) {
123 Out << " [autorelease -" << ACnt << ']';
124 }
125}
126
127namespace {
128class StopTrackingCallback final : public SymbolVisitor {
129 ProgramStateRef state;
130public:
131 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
132 ProgramStateRef getState() const { return state; }
133
134 bool VisitSymbol(SymbolRef sym) override {
George Karpenkovf153cdf2019-01-16 23:21:15 +0000135 state = removeRefBinding(state, sym);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000136 return true;
137 }
138};
139} // end anonymous namespace
140
141//===----------------------------------------------------------------------===//
142// Handle statements that may have an effect on refcounts.
143//===----------------------------------------------------------------------===//
144
145void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
146 CheckerContext &C) const {
147
148 // Scan the BlockDecRefExprs for any object the retain count checker
149 // may be tracking.
150 if (!BE->getBlockDecl()->hasCaptures())
151 return;
152
153 ProgramStateRef state = C.getState();
154 auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
155
156 BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
157 E = R->referenced_vars_end();
158
159 if (I == E)
160 return;
161
162 // FIXME: For now we invalidate the tracking of all symbols passed to blocks
163 // via captured variables, even though captured variables result in a copy
164 // and in implicit increment/decrement of a retain count.
165 SmallVector<const MemRegion*, 10> Regions;
166 const LocationContext *LC = C.getLocationContext();
167 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
168
169 for ( ; I != E; ++I) {
170 const VarRegion *VR = I.getCapturedRegion();
171 if (VR->getSuperRegion() == R) {
172 VR = MemMgr.getVarRegion(VR->getDecl(), LC);
173 }
174 Regions.push_back(VR);
175 }
176
George Karpenkovd3e76752018-10-23 23:12:12 +0000177 state = state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000178 C.addTransition(state);
179}
180
181void RetainCountChecker::checkPostStmt(const CastExpr *CE,
182 CheckerContext &C) const {
183 const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
184 if (!BE)
185 return;
186
George Karpenkov9cbcc212019-01-10 18:14:12 +0000187 ArgEffect AE = ArgEffect(IncRef, ObjKind::ObjC);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000188
189 switch (BE->getBridgeKind()) {
190 case OBC_Bridge:
191 // Do nothing.
192 return;
193 case OBC_BridgeRetained:
George Karpenkov9cbcc212019-01-10 18:14:12 +0000194 AE = AE.withKind(IncRef);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000195 break;
196 case OBC_BridgeTransfer:
George Karpenkov9cbcc212019-01-10 18:14:12 +0000197 AE = AE.withKind(DecRefBridgedTransferred);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000198 break;
199 }
200
201 ProgramStateRef state = C.getState();
202 SymbolRef Sym = C.getSVal(CE).getAsLocSymbol();
203 if (!Sym)
204 return;
205 const RefVal* T = getRefBinding(state, Sym);
206 if (!T)
207 return;
208
209 RefVal::Kind hasErr = (RefVal::Kind) 0;
210 state = updateSymbol(state, Sym, *T, AE, hasErr, C);
211
212 if (hasErr) {
213 // FIXME: If we get an error during a bridge cast, should we report it?
214 return;
215 }
216
217 C.addTransition(state);
218}
219
220void RetainCountChecker::processObjCLiterals(CheckerContext &C,
221 const Expr *Ex) const {
222 ProgramStateRef state = C.getState();
223 const ExplodedNode *pred = C.getPredecessor();
224 for (const Stmt *Child : Ex->children()) {
225 SVal V = pred->getSVal(Child);
226 if (SymbolRef sym = V.getAsSymbol())
227 if (const RefVal* T = getRefBinding(state, sym)) {
228 RefVal::Kind hasErr = (RefVal::Kind) 0;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000229 state = updateSymbol(state, sym, *T,
230 ArgEffect(MayEscape, ObjKind::ObjC), hasErr, C);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000231 if (hasErr) {
232 processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C);
233 return;
234 }
235 }
236 }
237
238 // Return the object as autoreleased.
George Karpenkov7e3016d2019-01-10 18:13:46 +0000239 // RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000240 if (SymbolRef sym =
241 state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
242 QualType ResultTy = Ex->getType();
243 state = setRefBinding(state, sym,
George Karpenkov7e3016d2019-01-10 18:13:46 +0000244 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
George Karpenkov70c2ee32018-08-17 21:41:07 +0000245 }
246
247 C.addTransition(state);
248}
249
250void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
251 CheckerContext &C) const {
252 // Apply the 'MayEscape' to all values.
253 processObjCLiterals(C, AL);
254}
255
256void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
257 CheckerContext &C) const {
258 // Apply the 'MayEscape' to all keys and values.
259 processObjCLiterals(C, DL);
260}
261
262void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
263 CheckerContext &C) const {
264 const ExplodedNode *Pred = C.getPredecessor();
265 ProgramStateRef State = Pred->getState();
266
267 if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) {
268 QualType ResultTy = Ex->getType();
269 State = setRefBinding(State, Sym,
George Karpenkov7e3016d2019-01-10 18:13:46 +0000270 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
George Karpenkov70c2ee32018-08-17 21:41:07 +0000271 }
272
273 C.addTransition(State);
274}
275
276void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
277 CheckerContext &C) const {
278 Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
279 if (!IVarLoc)
280 return;
281
282 ProgramStateRef State = C.getState();
283 SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
284 if (!Sym || !dyn_cast_or_null<ObjCIvarRegion>(Sym->getOriginRegion()))
285 return;
286
287 // Accessing an ivar directly is unusual. If we've done that, be more
288 // forgiving about what the surrounding code is allowed to do.
289
290 QualType Ty = Sym->getType();
George Karpenkov7e3016d2019-01-10 18:13:46 +0000291 ObjKind Kind;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000292 if (Ty->isObjCRetainableType())
George Karpenkov7e3016d2019-01-10 18:13:46 +0000293 Kind = ObjKind::ObjC;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000294 else if (coreFoundation::isCFObjectRef(Ty))
George Karpenkov7e3016d2019-01-10 18:13:46 +0000295 Kind = ObjKind::CF;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000296 else
297 return;
298
299 // If the value is already known to be nil, don't bother tracking it.
300 ConstraintManager &CMgr = State->getConstraintManager();
301 if (CMgr.isNull(State, Sym).isConstrainedTrue())
302 return;
303
304 if (const RefVal *RV = getRefBinding(State, Sym)) {
305 // If we've seen this symbol before, or we're only seeing it now because
306 // of something the analyzer has synthesized, don't do anything.
307 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None ||
308 isSynthesizedAccessor(C.getStackFrame())) {
309 return;
310 }
311
312 // Note that this value has been loaded from an ivar.
313 C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
314 return;
315 }
316
317 RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty);
318
319 // In a synthesized accessor, the effective retain count is +0.
320 if (isSynthesizedAccessor(C.getStackFrame())) {
321 C.addTransition(setRefBinding(State, Sym, PlusZero));
322 return;
323 }
324
325 State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
326 C.addTransition(State);
327}
328
329void RetainCountChecker::checkPostCall(const CallEvent &Call,
330 CheckerContext &C) const {
331 RetainSummaryManager &Summaries = getSummaryManager(C);
George Karpenkovefef49c2018-08-21 03:09:02 +0000332
333 // Leave null if no receiver.
334 QualType ReceiverType;
335 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
336 if (MC->isInstanceMessage()) {
337 SVal ReceiverV = MC->getReceiverSVal();
338 if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
339 if (const RefVal *T = getRefBinding(C.getState(), Sym))
340 ReceiverType = T->getType();
341 }
342 }
343
344 const RetainSummary *Summ = Summaries.getSummary(Call, ReceiverType);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000345
346 if (C.wasInlined) {
347 processSummaryOfInlined(*Summ, Call, C);
348 return;
349 }
350 checkSummary(*Summ, Call, C);
351}
352
353/// GetReturnType - Used to get the return type of a message expression or
354/// function call with the intention of affixing that type to a tracked symbol.
355/// While the return type can be queried directly from RetEx, when
356/// invoking class methods we augment to the return type to be that of
357/// a pointer to the class (as opposed it just being id).
358// FIXME: We may be able to do this with related result types instead.
359// This function is probably overestimating.
360static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
361 QualType RetTy = RetE->getType();
362 // If RetE is not a message expression just return its type.
363 // If RetE is a message expression, return its types if it is something
364 /// more specific than id.
365 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
366 if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
367 if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
368 PT->isObjCClassType()) {
369 // At this point we know the return type of the message expression is
370 // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
371 // is a call to a class method whose type we can resolve. In such
372 // cases, promote the return type to XXX* (where XXX is the class).
373 const ObjCInterfaceDecl *D = ME->getReceiverInterface();
374 return !D ? RetTy :
375 Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D));
376 }
377
378 return RetTy;
379}
380
George Karpenkov80c9e782018-08-22 01:16:49 +0000381static Optional<RefVal> refValFromRetEffect(RetEffect RE,
382 QualType ResultTy) {
383 if (RE.isOwned()) {
384 return RefVal::makeOwned(RE.getObjKind(), ResultTy);
385 } else if (RE.notOwned()) {
386 return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
387 }
388
389 return None;
390}
391
George Karpenkov255b0582018-12-21 19:13:40 +0000392static bool isPointerToObject(QualType QT) {
393 QualType PT = QT->getPointeeType();
394 if (!PT.isNull())
395 if (PT->getAsCXXRecordDecl())
396 return true;
397 return false;
398}
399
400/// Whether the tracked value should be escaped on a given call.
401/// OSObjects are escaped when passed to void * / etc.
George Karpenkov9cbcc212019-01-10 18:14:12 +0000402static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx,
George Karpenkov255b0582018-12-21 19:13:40 +0000403 const RefVal *TrackedValue) {
George Karpenkov7e3016d2019-01-10 18:13:46 +0000404 if (TrackedValue->getObjKind() != ObjKind::OS)
George Karpenkov255b0582018-12-21 19:13:40 +0000405 return false;
406 if (ArgIdx >= CE.parameters().size())
407 return false;
408 return !isPointerToObject(CE.parameters()[ArgIdx]->getType());
409}
410
George Karpenkov70c2ee32018-08-17 21:41:07 +0000411// We don't always get the exact modeling of the function with regards to the
412// retain count checker even when the function is inlined. For example, we need
413// to stop tracking the symbols which were marked with StopTrackingHard.
414void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
415 const CallEvent &CallOrMsg,
416 CheckerContext &C) const {
417 ProgramStateRef state = C.getState();
418
419 // Evaluate the effect of the arguments.
420 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
George Karpenkov255b0582018-12-21 19:13:40 +0000421 SVal V = CallOrMsg.getArgSVal(idx);
422
423 if (SymbolRef Sym = V.getAsLocSymbol()) {
George Karpenkov585a2102019-01-10 18:13:59 +0000424 bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard;
George Karpenkov255b0582018-12-21 19:13:40 +0000425 if (const RefVal *T = getRefBinding(state, Sym))
George Karpenkov9cbcc212019-01-10 18:14:12 +0000426 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
George Karpenkov255b0582018-12-21 19:13:40 +0000427 ShouldRemoveBinding = true;
428
429 if (ShouldRemoveBinding)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000430 state = removeRefBinding(state, Sym);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000431 }
432 }
433
434 // Evaluate the effect on the message receiver.
George Karpenkov6e9fd132018-08-22 01:17:09 +0000435 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000436 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
George Karpenkov585a2102019-01-10 18:13:59 +0000437 if (Summ.getReceiverEffect().getKind() == StopTrackingHard) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000438 state = removeRefBinding(state, Sym);
439 }
440 }
441 }
442
443 // Consult the summary for the return value.
444 RetEffect RE = Summ.getRetEffect();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000445
George Karpenkovd5ef0d22018-08-29 20:28:33 +0000446 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
George Karpenkovd5ef0d22018-08-29 20:28:33 +0000447 if (RE.getKind() == RetEffect::NoRetHard)
448 state = removeRefBinding(state, Sym);
449 }
George Karpenkovab0011e2018-08-23 00:26:59 +0000450
George Karpenkov70c2ee32018-08-17 21:41:07 +0000451 C.addTransition(state);
452}
453
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000454static bool isSmartPtrField(const MemRegion *MR) {
455 const auto *TR = dyn_cast<TypedValueRegion>(
456 cast<SubRegion>(MR)->getSuperRegion());
457 return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType());
458}
459
460
George Karpenkov03391512019-01-16 23:21:38 +0000461/// A value escapes in these possible cases:
462///
463/// - binding to something that is not a memory region.
464/// - binding to a memregion that does not have stack storage
465/// - binding to a variable that has a destructor attached using CleanupAttr
466///
467/// We do not currently model what happens when a symbol is
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000468/// assigned to a struct field, unless it is a known smart pointer
469/// implementation, about which we know that it is inlined.
George Karpenkov03391512019-01-16 23:21:38 +0000470/// FIXME: This could definitely be improved upon.
George Karpenkov5be959c2019-01-11 23:35:17 +0000471static bool shouldEscapeRegion(const MemRegion *R) {
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000472 if (isSmartPtrField(R))
473 return false;
474
George Karpenkov03391512019-01-16 23:21:38 +0000475 const auto *VR = dyn_cast<VarRegion>(R);
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000476
George Karpenkov03391512019-01-16 23:21:38 +0000477 if (!R->hasStackStorage() || !VR)
478 return true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000479
George Karpenkov03391512019-01-16 23:21:38 +0000480 const VarDecl *VD = VR->getDecl();
481 if (!VD->hasAttr<CleanupAttr>())
482 return false; // CleanupAttr attaches destructors, which cause escaping.
483 return true;
George Karpenkov5be959c2019-01-11 23:35:17 +0000484}
George Karpenkov70c2ee32018-08-17 21:41:07 +0000485
George Karpenkov5be959c2019-01-11 23:35:17 +0000486static SmallVector<ProgramStateRef, 2>
487updateOutParameters(ProgramStateRef State, const RetainSummary &Summ,
488 const CallEvent &CE) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000489
George Karpenkov5be959c2019-01-11 23:35:17 +0000490 SVal L = CE.getReturnValue();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000491
George Karpenkov5be959c2019-01-11 23:35:17 +0000492 // Splitting is required to support out parameters,
493 // as out parameters might be created only on the "success" branch.
494 // We want to avoid eagerly splitting unless out parameters are actually
495 // needed.
496 bool SplitNecessary = false;
497 for (auto &P : Summ.getArgEffects())
498 if (P.second.getKind() == RetainedOutParameterOnNonZero ||
499 P.second.getKind() == RetainedOutParameterOnZero)
500 SplitNecessary = true;
501
502 ProgramStateRef AssumeNonZeroReturn = State;
503 ProgramStateRef AssumeZeroReturn = State;
504
505 if (SplitNecessary) {
506 if (auto DL = L.getAs<DefinedOrUnknownSVal>()) {
507 AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true);
508 AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false);
509 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000510 }
511
George Karpenkov5be959c2019-01-11 23:35:17 +0000512 for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) {
513 SVal ArgVal = CE.getArgSVal(idx);
514 ArgEffect AE = Summ.getArg(idx);
515
516 auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion());
517 if (!ArgRegion)
518 continue;
519
520 QualType PointeeTy = ArgRegion->getValueType();
521 SVal PointeeVal = State->getSVal(ArgRegion);
522 SymbolRef Pointee = PointeeVal.getAsLocSymbol();
523 if (!Pointee)
524 continue;
525
526 if (shouldEscapeRegion(ArgRegion))
527 continue;
528
529 auto makeNotOwnedParameter = [&](ProgramStateRef St) {
530 return setRefBinding(St, Pointee,
531 RefVal::makeNotOwned(AE.getObjKind(), PointeeTy));
532 };
533 auto makeOwnedParameter = [&](ProgramStateRef St) {
534 return setRefBinding(St, Pointee,
535 RefVal::makeOwned(ObjKind::OS, PointeeTy));
536 };
537
538 switch (AE.getKind()) {
539 case UnretainedOutParameter:
540 AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
541 AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
542 break;
543 case RetainedOutParameter:
544 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
545 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
546 break;
547 case RetainedOutParameterOnNonZero:
548 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
549 break;
550 case RetainedOutParameterOnZero:
551 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
552 break;
553 default:
554 break;
555 }
556 }
557
558 if (SplitNecessary) {
559 return {AssumeNonZeroReturn, AssumeZeroReturn};
560 } else {
561 assert(AssumeZeroReturn == AssumeNonZeroReturn);
562 return {AssumeZeroReturn};
563 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000564}
565
566void RetainCountChecker::checkSummary(const RetainSummary &Summ,
567 const CallEvent &CallOrMsg,
568 CheckerContext &C) const {
569 ProgramStateRef state = C.getState();
570
571 // Evaluate the effect of the arguments.
572 RefVal::Kind hasErr = (RefVal::Kind) 0;
573 SourceRange ErrorRange;
574 SymbolRef ErrorSym = nullptr;
575
George Karpenkov717c4c02019-01-10 18:15:17 +0000576 // Helper tag for providing diagnostics: indicate whether dealloc was sent
577 // at this location.
578 static CheckerProgramPointTag DeallocSentTag(this, DeallocTagDescription);
579 bool DeallocSent = false;
580
George Karpenkov70c2ee32018-08-17 21:41:07 +0000581 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
582 SVal V = CallOrMsg.getArgSVal(idx);
583
George Karpenkov9cbcc212019-01-10 18:14:12 +0000584 ArgEffect Effect = Summ.getArg(idx);
George Karpenkov5be959c2019-01-11 23:35:17 +0000585 if (SymbolRef Sym = V.getAsLocSymbol()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000586 if (const RefVal *T = getRefBinding(state, Sym)) {
George Karpenkov041c9fa2018-12-08 01:18:40 +0000587
George Karpenkov9cbcc212019-01-10 18:14:12 +0000588 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
589 Effect = ArgEffect(StopTrackingHard, ObjKind::OS);
George Karpenkov041c9fa2018-12-08 01:18:40 +0000590
George Karpenkov70c2ee32018-08-17 21:41:07 +0000591 state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
592 if (hasErr) {
593 ErrorRange = CallOrMsg.getArgSourceRange(idx);
594 ErrorSym = Sym;
595 break;
George Karpenkov717c4c02019-01-10 18:15:17 +0000596 } else if (Effect.getKind() == Dealloc) {
597 DeallocSent = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000598 }
599 }
600 }
601 }
602
George Karpenkovab0011e2018-08-23 00:26:59 +0000603 // Evaluate the effect on the message receiver / `this` argument.
George Karpenkov70c2ee32018-08-17 21:41:07 +0000604 bool ReceiverIsTracked = false;
605 if (!hasErr) {
George Karpenkovab0011e2018-08-23 00:26:59 +0000606 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000607 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
608 if (const RefVal *T = getRefBinding(state, Sym)) {
609 ReceiverIsTracked = true;
George Karpenkov585a2102019-01-10 18:13:59 +0000610 state = updateSymbol(state, Sym, *T,
George Karpenkov9cbcc212019-01-10 18:14:12 +0000611 Summ.getReceiverEffect(), hasErr, C);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000612 if (hasErr) {
613 ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
614 ErrorSym = Sym;
George Karpenkov717c4c02019-01-10 18:15:17 +0000615 } else if (Summ.getReceiverEffect().getKind() == Dealloc) {
616 DeallocSent = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000617 }
618 }
619 }
George Karpenkovab0011e2018-08-23 00:26:59 +0000620 } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
621 if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
622 if (const RefVal *T = getRefBinding(state, Sym)) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000623 state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
George Karpenkovab0011e2018-08-23 00:26:59 +0000624 hasErr, C);
625 if (hasErr) {
626 ErrorRange = MCall->getOriginExpr()->getSourceRange();
627 ErrorSym = Sym;
628 }
629 }
630 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000631 }
632 }
633
634 // Process any errors.
635 if (hasErr) {
636 processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
637 return;
638 }
639
640 // Consult the summary for the return value.
641 RetEffect RE = Summ.getRetEffect();
642
643 if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
644 if (ReceiverIsTracked)
645 RE = getSummaryManager(C).getObjAllocRetEffect();
646 else
647 RE = RetEffect::MakeNoRet();
648 }
649
George Karpenkov80c9e782018-08-22 01:16:49 +0000650 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
651 QualType ResultTy = CallOrMsg.getResultType();
652 if (RE.notOwned()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000653 const Expr *Ex = CallOrMsg.getOriginExpr();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000654 assert(Ex);
George Karpenkov80c9e782018-08-22 01:16:49 +0000655 ResultTy = GetReturnType(Ex, C.getASTContext());
George Karpenkov70c2ee32018-08-17 21:41:07 +0000656 }
George Karpenkov80c9e782018-08-22 01:16:49 +0000657 if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
658 state = setRefBinding(state, Sym, *updatedRefVal);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000659 }
660
George Karpenkov5be959c2019-01-11 23:35:17 +0000661 SmallVector<ProgramStateRef, 2> Out =
662 updateOutParameters(state, Summ, CallOrMsg);
663
664 for (ProgramStateRef St : Out) {
665 if (DeallocSent) {
666 C.addTransition(St, C.getPredecessor(), &DeallocSentTag);
667 } else {
668 C.addTransition(St);
669 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000670 }
671}
672
George Karpenkov585a2102019-01-10 18:13:59 +0000673ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
674 SymbolRef sym, RefVal V,
George Karpenkov9cbcc212019-01-10 18:14:12 +0000675 ArgEffect AE,
George Karpenkov585a2102019-01-10 18:13:59 +0000676 RefVal::Kind &hasErr,
677 CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000678 bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000679 if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) {
680 switch (AE.getKind()) {
681 default:
682 break;
683 case IncRef:
684 AE = AE.withKind(DoNothing);
685 break;
686 case DecRef:
687 AE = AE.withKind(DoNothing);
688 break;
689 case DecRefAndStopTrackingHard:
690 AE = AE.withKind(StopTracking);
691 break;
692 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000693 }
694
695 // Handle all use-after-releases.
696 if (V.getKind() == RefVal::Released) {
697 V = V ^ RefVal::ErrorUseAfterRelease;
698 hasErr = V.getKind();
699 return setRefBinding(state, sym, V);
700 }
701
George Karpenkov9cbcc212019-01-10 18:14:12 +0000702 switch (AE.getKind()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000703 case UnretainedOutParameter:
704 case RetainedOutParameter:
George Karpenkov5be959c2019-01-11 23:35:17 +0000705 case RetainedOutParameterOnZero:
706 case RetainedOutParameterOnNonZero:
George Karpenkov70c2ee32018-08-17 21:41:07 +0000707 llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
708 "not have ref state.");
709
George Karpenkov717c4c02019-01-10 18:15:17 +0000710 case Dealloc: // NB. we only need to add a note in a non-error case.
George Karpenkov70c2ee32018-08-17 21:41:07 +0000711 switch (V.getKind()) {
712 default:
713 llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
714 case RefVal::Owned:
715 // The object immediately transitions to the released state.
716 V = V ^ RefVal::Released;
717 V.clearCounts();
718 return setRefBinding(state, sym, V);
719 case RefVal::NotOwned:
720 V = V ^ RefVal::ErrorDeallocNotOwned;
721 hasErr = V.getKind();
722 break;
723 }
724 break;
725
726 case MayEscape:
727 if (V.getKind() == RefVal::Owned) {
728 V = V ^ RefVal::NotOwned;
729 break;
730 }
731
Reid Kleckner4dc0b1a2018-11-01 19:54:45 +0000732 LLVM_FALLTHROUGH;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000733
734 case DoNothing:
735 return state;
736
737 case Autorelease:
738 // Update the autorelease counts.
739 V = V.autorelease();
740 break;
741
742 case StopTracking:
743 case StopTrackingHard:
744 return removeRefBinding(state, sym);
745
746 case IncRef:
747 switch (V.getKind()) {
748 default:
749 llvm_unreachable("Invalid RefVal state for a retain.");
750 case RefVal::Owned:
751 case RefVal::NotOwned:
752 V = V + 1;
753 break;
754 }
755 break;
756
757 case DecRef:
758 case DecRefBridgedTransferred:
759 case DecRefAndStopTrackingHard:
760 switch (V.getKind()) {
761 default:
762 // case 'RefVal::Released' handled above.
763 llvm_unreachable("Invalid RefVal state for a release.");
764
765 case RefVal::Owned:
766 assert(V.getCount() > 0);
767 if (V.getCount() == 1) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000768 if (AE.getKind() == DecRefBridgedTransferred ||
George Karpenkov70c2ee32018-08-17 21:41:07 +0000769 V.getIvarAccessHistory() ==
770 RefVal::IvarAccessHistory::AccessedDirectly)
771 V = V ^ RefVal::NotOwned;
772 else
773 V = V ^ RefVal::Released;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000774 } else if (AE.getKind() == DecRefAndStopTrackingHard) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000775 return removeRefBinding(state, sym);
776 }
777
778 V = V - 1;
779 break;
780
781 case RefVal::NotOwned:
782 if (V.getCount() > 0) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000783 if (AE.getKind() == DecRefAndStopTrackingHard)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000784 return removeRefBinding(state, sym);
785 V = V - 1;
786 } else if (V.getIvarAccessHistory() ==
787 RefVal::IvarAccessHistory::AccessedDirectly) {
788 // Assume that the instance variable was holding on the object at
789 // +1, and we just didn't know.
George Karpenkov9cbcc212019-01-10 18:14:12 +0000790 if (AE.getKind() == DecRefAndStopTrackingHard)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000791 return removeRefBinding(state, sym);
792 V = V.releaseViaIvar() ^ RefVal::Released;
793 } else {
794 V = V ^ RefVal::ErrorReleaseNotOwned;
795 hasErr = V.getKind();
796 }
797 break;
798 }
799 break;
800 }
801 return setRefBinding(state, sym, V);
802}
803
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000804const RefCountBug &
805RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
806 SymbolRef Sym) const {
807 switch (ErrorKind) {
808 case RefVal::ErrorUseAfterRelease:
809 return useAfterRelease;
810 case RefVal::ErrorReleaseNotOwned:
811 return releaseNotOwned;
812 case RefVal::ErrorDeallocNotOwned:
813 if (Sym->getType()->getPointeeCXXRecordDecl())
814 return freeNotOwned;
815 return deallocNotOwned;
816 default:
817 llvm_unreachable("Unhandled error.");
818 }
819}
820
George Karpenkov70c2ee32018-08-17 21:41:07 +0000821void RetainCountChecker::processNonLeakError(ProgramStateRef St,
822 SourceRange ErrorRange,
823 RefVal::Kind ErrorKind,
824 SymbolRef Sym,
825 CheckerContext &C) const {
826 // HACK: Ignore retain-count issues on values accessed through ivars,
827 // because of cases like this:
828 // [_contentView retain];
829 // [_contentView removeFromSuperview];
830 // [self addSubview:_contentView]; // invalidates 'self'
831 // [_contentView release];
832 if (const RefVal *RV = getRefBinding(St, Sym))
833 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
834 return;
835
836 ExplodedNode *N = C.generateErrorNode(St);
837 if (!N)
838 return;
839
George Karpenkov0bb17c42019-01-10 18:16:25 +0000840 auto report = llvm::make_unique<RefCountReport>(
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000841 errorKindToBugKind(ErrorKind, Sym),
842 C.getASTContext().getLangOpts(), N, Sym);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000843 report->addRange(ErrorRange);
844 C.emitReport(std::move(report));
845}
846
847//===----------------------------------------------------------------------===//
848// Handle the return values of retain-count-related functions.
849//===----------------------------------------------------------------------===//
850
851bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
852 // Get the callee. We're only interested in simple C functions.
853 ProgramStateRef state = C.getState();
854 const FunctionDecl *FD = C.getCalleeDecl(CE);
855 if (!FD)
856 return false;
857
George Karpenkovc4d6b932018-08-17 21:42:05 +0000858 RetainSummaryManager &SmrMgr = getSummaryManager(C);
859 QualType ResultTy = CE->getCallReturnType(C.getASTContext());
George Karpenkov70c2ee32018-08-17 21:41:07 +0000860
George Karpenkov70c2ee32018-08-17 21:41:07 +0000861 // See if the function has 'rc_ownership_trusted_implementation'
862 // annotate attribute. If it does, we will not inline it.
863 bool hasTrustedImplementationAnnotation = false;
864
George Karpenkov41dc8de2018-10-11 22:59:16 +0000865 const LocationContext *LCtx = C.getLocationContext();
866
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000867 using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
868 Optional<BehaviorSummary> BSmr =
869 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
870
George Karpenkovc4d6b932018-08-17 21:42:05 +0000871 // See if it's one of the specific functions we know how to eval.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000872 if (!BSmr)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000873 return false;
874
875 // Bind the return value.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000876 if (BSmr == BehaviorSummary::Identity ||
877 BSmr == BehaviorSummary::IdentityOrZero) {
George Karpenkov48de5822018-10-23 23:11:30 +0000878 SVal RetVal = state->getSVal(CE->getArg(0), LCtx);
879
George Karpenkov70c2ee32018-08-17 21:41:07 +0000880 // If the receiver is unknown or the function has
881 // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
882 // return value.
George Karpenkov48de5822018-10-23 23:11:30 +0000883 if (RetVal.isUnknown() ||
884 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
885 SValBuilder &SVB = C.getSValBuilder();
886 RetVal =
887 SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
888 }
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000889 state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
890
891 if (BSmr == BehaviorSummary::IdentityOrZero) {
892 // Add a branch where the output is zero.
893 ProgramStateRef NullOutputState = C.getState();
894
895 // Assume that output is zero on the other branch.
896 NullOutputState = NullOutputState->BindExpr(
897 CE, LCtx, C.getSValBuilder().makeNull(), /*Invalidate=*/false);
898
899 C.addTransition(NullOutputState);
900
901 // And on the original branch assume that both input and
902 // output are non-zero.
903 if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
904 state = state->assume(*L, /*Assumption=*/true);
905
906 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000907 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000908
George Karpenkov70c2ee32018-08-17 21:41:07 +0000909 C.addTransition(state);
910 return true;
911}
912
George Karpenkov04553e52018-09-21 20:37:20 +0000913ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
914 CheckerContext &C) const {
915 ExplodedNode *Pred = C.getPredecessor();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000916
917 // Only adjust the reference count if this is the top-level call frame,
918 // and not the result of inlining. In the future, we should do
919 // better checking even for inlined calls, and see if they match
920 // with their expected semantics (e.g., the method should return a retained
921 // object, etc.).
922 if (!C.inTopFrame())
George Karpenkov04553e52018-09-21 20:37:20 +0000923 return Pred;
924
925 if (!S)
926 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000927
928 const Expr *RetE = S->getRetValue();
929 if (!RetE)
George Karpenkov04553e52018-09-21 20:37:20 +0000930 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000931
932 ProgramStateRef state = C.getState();
933 SymbolRef Sym =
934 state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol();
935 if (!Sym)
George Karpenkov04553e52018-09-21 20:37:20 +0000936 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000937
938 // Get the reference count binding (if any).
939 const RefVal *T = getRefBinding(state, Sym);
940 if (!T)
George Karpenkov04553e52018-09-21 20:37:20 +0000941 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000942
943 // Change the reference count.
944 RefVal X = *T;
945
946 switch (X.getKind()) {
947 case RefVal::Owned: {
948 unsigned cnt = X.getCount();
949 assert(cnt > 0);
950 X.setCount(cnt - 1);
951 X = X ^ RefVal::ReturnedOwned;
952 break;
953 }
954
955 case RefVal::NotOwned: {
956 unsigned cnt = X.getCount();
957 if (cnt) {
958 X.setCount(cnt - 1);
959 X = X ^ RefVal::ReturnedOwned;
George Karpenkov04553e52018-09-21 20:37:20 +0000960 } else {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000961 X = X ^ RefVal::ReturnedNotOwned;
962 }
963 break;
964 }
965
966 default:
George Karpenkov04553e52018-09-21 20:37:20 +0000967 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000968 }
969
970 // Update the binding.
971 state = setRefBinding(state, Sym, X);
George Karpenkov04553e52018-09-21 20:37:20 +0000972 Pred = C.addTransition(state);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000973
974 // At this point we have updated the state properly.
975 // Everything after this is merely checking to see if the return value has
976 // been over- or under-retained.
977
978 // Did we cache out?
979 if (!Pred)
George Karpenkov04553e52018-09-21 20:37:20 +0000980 return nullptr;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000981
982 // Update the autorelease counts.
983 static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease");
George Karpenkov04553e52018-09-21 20:37:20 +0000984 state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000985
George Karpenkov04553e52018-09-21 20:37:20 +0000986 // Have we generated a sink node?
George Karpenkov70c2ee32018-08-17 21:41:07 +0000987 if (!state)
George Karpenkov04553e52018-09-21 20:37:20 +0000988 return nullptr;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000989
990 // Get the updated binding.
991 T = getRefBinding(state, Sym);
992 assert(T);
993 X = *T;
994
995 // Consult the summary of the enclosing method.
996 RetainSummaryManager &Summaries = getSummaryManager(C);
997 const Decl *CD = &Pred->getCodeDecl();
998 RetEffect RE = RetEffect::MakeNoRet();
999
1000 // FIXME: What is the convention for blocks? Is there one?
1001 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
1002 const RetainSummary *Summ = Summaries.getMethodSummary(MD);
1003 RE = Summ->getRetEffect();
1004 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
1005 if (!isa<CXXMethodDecl>(FD)) {
1006 const RetainSummary *Summ = Summaries.getFunctionSummary(FD);
1007 RE = Summ->getRetEffect();
1008 }
1009 }
1010
George Karpenkov04553e52018-09-21 20:37:20 +00001011 return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001012}
1013
George Karpenkov04553e52018-09-21 20:37:20 +00001014ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
George Karpenkov70c2ee32018-08-17 21:41:07 +00001015 CheckerContext &C,
1016 ExplodedNode *Pred,
1017 RetEffect RE, RefVal X,
1018 SymbolRef Sym,
1019 ProgramStateRef state) const {
1020 // HACK: Ignore retain-count issues on values accessed through ivars,
1021 // because of cases like this:
1022 // [_contentView retain];
1023 // [_contentView removeFromSuperview];
1024 // [self addSubview:_contentView]; // invalidates 'self'
1025 // [_contentView release];
1026 if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
George Karpenkov04553e52018-09-21 20:37:20 +00001027 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001028
1029 // Any leaks or other errors?
1030 if (X.isReturnedOwned() && X.getCount() == 0) {
1031 if (RE.getKind() != RetEffect::NoRet) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001032 if (!RE.isOwned()) {
George Karpenkov04553e52018-09-21 20:37:20 +00001033
George Karpenkov70c2ee32018-08-17 21:41:07 +00001034 // The returning type is a CF, we expect the enclosing method should
1035 // return ownership.
George Karpenkov70c2ee32018-08-17 21:41:07 +00001036 X = X ^ RefVal::ErrorLeakReturned;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001037
George Karpenkov70c2ee32018-08-17 21:41:07 +00001038 // Generate an error node.
1039 state = setRefBinding(state, Sym, X);
1040
1041 static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak");
1042 ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
1043 if (N) {
1044 const LangOptions &LOpts = C.getASTContext().getLangOpts();
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001045 auto R =
1046 llvm::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C);
George Karpenkov04553e52018-09-21 20:37:20 +00001047 C.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001048 }
George Karpenkov04553e52018-09-21 20:37:20 +00001049 return N;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001050 }
1051 }
1052 } else if (X.isReturnedNotOwned()) {
1053 if (RE.isOwned()) {
1054 if (X.getIvarAccessHistory() ==
1055 RefVal::IvarAccessHistory::AccessedDirectly) {
1056 // Assume the method was trying to transfer a +1 reference from a
1057 // strong ivar to the caller.
1058 state = setRefBinding(state, Sym,
1059 X.releaseViaIvar() ^ RefVal::ReturnedOwned);
1060 } else {
1061 // Trying to return a not owned object to a caller expecting an
1062 // owned object.
1063 state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
1064
1065 static CheckerProgramPointTag
1066 ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned");
1067
1068 ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
1069 if (N) {
George Karpenkov0bb17c42019-01-10 18:16:25 +00001070 auto R = llvm::make_unique<RefCountReport>(
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001071 returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
George Karpenkov04553e52018-09-21 20:37:20 +00001072 C.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001073 }
George Karpenkov04553e52018-09-21 20:37:20 +00001074 return N;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001075 }
1076 }
1077 }
George Karpenkov04553e52018-09-21 20:37:20 +00001078 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001079}
1080
1081//===----------------------------------------------------------------------===//
1082// Check various ways a symbol can be invalidated.
1083//===----------------------------------------------------------------------===//
1084
1085void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
1086 CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001087 ProgramStateRef state = C.getState();
George Karpenkov03391512019-01-16 23:21:38 +00001088 const MemRegion *MR = loc.getAsRegion();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001089
George Karpenkov03391512019-01-16 23:21:38 +00001090 // Find all symbols referenced by 'val' that we are tracking
George Karpenkov70c2ee32018-08-17 21:41:07 +00001091 // and stop tracking them.
George Karpenkov03391512019-01-16 23:21:38 +00001092 if (MR && shouldEscapeRegion(MR)) {
1093 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
1094 C.addTransition(state);
1095 }
George Karpenkov70c2ee32018-08-17 21:41:07 +00001096}
1097
1098ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
George Karpenkov6e9fd132018-08-22 01:17:09 +00001099 SVal Cond,
1100 bool Assumption) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001101 // FIXME: We may add to the interface of evalAssume the list of symbols
1102 // whose assumptions have changed. For now we just iterate through the
1103 // bindings and check if any of the tracked symbols are NULL. This isn't
1104 // too bad since the number of symbols we will track in practice are
1105 // probably small and evalAssume is only called at branches and a few
1106 // other places.
1107 RefBindingsTy B = state->get<RefBindings>();
1108
1109 if (B.isEmpty())
1110 return state;
1111
1112 bool changed = false;
1113 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
George Karpenkov03391512019-01-16 23:21:38 +00001114 ConstraintManager &CMgr = state->getConstraintManager();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001115
George Karpenkov03391512019-01-16 23:21:38 +00001116 for (auto &I : B) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001117 // Check if the symbol is null stop tracking the symbol.
George Karpenkov03391512019-01-16 23:21:38 +00001118 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001119 if (AllocFailed.isConstrainedTrue()) {
1120 changed = true;
George Karpenkov03391512019-01-16 23:21:38 +00001121 B = RefBFactory.remove(B, I.first);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001122 }
1123 }
1124
1125 if (changed)
1126 state = state->set<RefBindings>(B);
1127
1128 return state;
1129}
1130
George Karpenkovf153cdf2019-01-16 23:21:15 +00001131ProgramStateRef RetainCountChecker::checkRegionChanges(
1132 ProgramStateRef state, const InvalidatedSymbols *invalidated,
1133 ArrayRef<const MemRegion *> ExplicitRegions,
1134 ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
1135 const CallEvent *Call) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001136 if (!invalidated)
1137 return state;
1138
1139 llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001140
George Karpenkovf153cdf2019-01-16 23:21:15 +00001141 for (const MemRegion *I : ExplicitRegions)
1142 if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
1143 WhitelistedSymbols.insert(SR->getSymbol());
1144
1145 for (SymbolRef sym : *invalidated) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001146 if (WhitelistedSymbols.count(sym))
1147 continue;
1148 // Remove any existing reference-count binding.
1149 state = removeRefBinding(state, sym);
1150 }
1151 return state;
1152}
1153
George Karpenkov70c2ee32018-08-17 21:41:07 +00001154ProgramStateRef
1155RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
1156 ExplodedNode *Pred,
1157 const ProgramPointTag *Tag,
1158 CheckerContext &Ctx,
George Karpenkov04553e52018-09-21 20:37:20 +00001159 SymbolRef Sym,
1160 RefVal V,
1161 const ReturnStmt *S) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001162 unsigned ACnt = V.getAutoreleaseCount();
1163
1164 // No autorelease counts? Nothing to be done.
1165 if (!ACnt)
1166 return state;
1167
1168 unsigned Cnt = V.getCount();
1169
1170 // FIXME: Handle sending 'autorelease' to already released object.
1171
1172 if (V.getKind() == RefVal::ReturnedOwned)
1173 ++Cnt;
1174
1175 // If we would over-release here, but we know the value came from an ivar,
1176 // assume it was a strong ivar that's just been relinquished.
1177 if (ACnt > Cnt &&
1178 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
1179 V = V.releaseViaIvar();
1180 --ACnt;
1181 }
1182
1183 if (ACnt <= Cnt) {
1184 if (ACnt == Cnt) {
1185 V.clearCounts();
George Karpenkov04553e52018-09-21 20:37:20 +00001186 if (V.getKind() == RefVal::ReturnedOwned) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001187 V = V ^ RefVal::ReturnedNotOwned;
George Karpenkov04553e52018-09-21 20:37:20 +00001188 } else {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001189 V = V ^ RefVal::NotOwned;
George Karpenkov04553e52018-09-21 20:37:20 +00001190 }
George Karpenkov70c2ee32018-08-17 21:41:07 +00001191 } else {
1192 V.setCount(V.getCount() - ACnt);
1193 V.setAutoreleaseCount(0);
1194 }
1195 return setRefBinding(state, Sym, V);
1196 }
1197
1198 // HACK: Ignore retain-count issues on values accessed through ivars,
1199 // because of cases like this:
1200 // [_contentView retain];
1201 // [_contentView removeFromSuperview];
1202 // [self addSubview:_contentView]; // invalidates 'self'
1203 // [_contentView release];
1204 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1205 return state;
1206
1207 // Woah! More autorelease counts then retain counts left.
1208 // Emit hard error.
1209 V = V ^ RefVal::ErrorOverAutorelease;
1210 state = setRefBinding(state, Sym, V);
1211
1212 ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
1213 if (N) {
1214 SmallString<128> sbuf;
1215 llvm::raw_svector_ostream os(sbuf);
1216 os << "Object was autoreleased ";
1217 if (V.getAutoreleaseCount() > 1)
1218 os << V.getAutoreleaseCount() << " times but the object ";
1219 else
1220 os << "but ";
1221 os << "has a +" << V.getCount() << " retain count";
1222
George Karpenkov70c2ee32018-08-17 21:41:07 +00001223 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001224 auto R = llvm::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym,
1225 os.str());
George Karpenkov04553e52018-09-21 20:37:20 +00001226 Ctx.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001227 }
1228
1229 return nullptr;
1230}
1231
1232ProgramStateRef
1233RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
1234 SymbolRef sid, RefVal V,
1235 SmallVectorImpl<SymbolRef> &Leaked) const {
1236 bool hasLeak;
1237
1238 // HACK: Ignore retain-count issues on values accessed through ivars,
1239 // because of cases like this:
1240 // [_contentView retain];
1241 // [_contentView removeFromSuperview];
1242 // [self addSubview:_contentView]; // invalidates 'self'
1243 // [_contentView release];
1244 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1245 hasLeak = false;
1246 else if (V.isOwned())
1247 hasLeak = true;
1248 else if (V.isNotOwned() || V.isReturnedOwned())
1249 hasLeak = (V.getCount() > 0);
1250 else
1251 hasLeak = false;
1252
1253 if (!hasLeak)
1254 return removeRefBinding(state, sid);
1255
1256 Leaked.push_back(sid);
1257 return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
1258}
1259
1260ExplodedNode *
1261RetainCountChecker::processLeaks(ProgramStateRef state,
1262 SmallVectorImpl<SymbolRef> &Leaked,
1263 CheckerContext &Ctx,
1264 ExplodedNode *Pred) const {
1265 // Generate an intermediate node representing the leak point.
1266 ExplodedNode *N = Ctx.addTransition(state, Pred);
George Karpenkovf153cdf2019-01-16 23:21:15 +00001267 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001268
1269 if (N) {
George Karpenkovf153cdf2019-01-16 23:21:15 +00001270 for (SymbolRef L : Leaked) {
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001271 const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn;
1272 Ctx.emitReport(llvm::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001273 }
1274 }
1275
1276 return N;
1277}
1278
George Karpenkovb1b791b2018-08-17 21:43:27 +00001279static bool isISLObjectRef(QualType Ty) {
1280 return StringRef(Ty.getAsString()).startswith("isl_");
George Karpenkov70c2ee32018-08-17 21:41:07 +00001281}
1282
1283void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
1284 if (!Ctx.inTopFrame())
1285 return;
1286
George Karpenkovc4d6b932018-08-17 21:42:05 +00001287 RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001288 const LocationContext *LCtx = Ctx.getLocationContext();
1289 const FunctionDecl *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
1290
George Karpenkovc4d6b932018-08-17 21:42:05 +00001291 if (!FD || SmrMgr.isTrustedReferenceCountImplementation(FD))
George Karpenkov70c2ee32018-08-17 21:41:07 +00001292 return;
1293
1294 ProgramStateRef state = Ctx.getState();
George Karpenkovc4d6b932018-08-17 21:42:05 +00001295 const RetainSummary *FunctionSummary = SmrMgr.getFunctionSummary(FD);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001296 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
1297
1298 for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) {
1299 const ParmVarDecl *Param = FD->getParamDecl(idx);
1300 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
1301
1302 QualType Ty = Param->getType();
1303 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
George Karpenkov585a2102019-01-10 18:13:59 +00001304 if (AE && AE->getKind() == DecRef && isISLObjectRef(Ty)) {
George Karpenkov6e9fd132018-08-22 01:17:09 +00001305 state = setRefBinding(
George Karpenkov7e3016d2019-01-10 18:13:46 +00001306 state, Sym, RefVal::makeOwned(ObjKind::Generalized, Ty));
George Karpenkovb1b791b2018-08-17 21:43:27 +00001307 } else if (isISLObjectRef(Ty)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001308 state = setRefBinding(
1309 state, Sym,
George Karpenkov7e3016d2019-01-10 18:13:46 +00001310 RefVal::makeNotOwned(ObjKind::Generalized, Ty));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001311 }
1312 }
1313
1314 Ctx.addTransition(state);
1315}
1316
1317void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
1318 CheckerContext &Ctx) const {
George Karpenkov04553e52018-09-21 20:37:20 +00001319 ExplodedNode *Pred = processReturn(RS, Ctx);
1320
1321 // Created state cached out.
1322 if (!Pred) {
1323 return;
1324 }
1325
1326 ProgramStateRef state = Pred->getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001327 RefBindingsTy B = state->get<RefBindings>();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001328
1329 // Don't process anything within synthesized bodies.
1330 const LocationContext *LCtx = Pred->getLocationContext();
1331 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
1332 assert(!LCtx->inTopFrame());
1333 return;
1334 }
1335
George Karpenkov03391512019-01-16 23:21:38 +00001336 for (auto &I : B) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001337 state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx,
George Karpenkov03391512019-01-16 23:21:38 +00001338 I.first, I.second);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001339 if (!state)
1340 return;
1341 }
1342
1343 // If the current LocationContext has a parent, don't check for leaks.
1344 // We will do that later.
1345 // FIXME: we should instead check for imbalances of the retain/releases,
1346 // and suggest annotations.
1347 if (LCtx->getParent())
1348 return;
1349
1350 B = state->get<RefBindings>();
1351 SmallVector<SymbolRef, 10> Leaked;
1352
George Karpenkov03391512019-01-16 23:21:38 +00001353 for (auto &I : B)
1354 state = handleSymbolDeath(state, I.first, I.second, Leaked);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001355
1356 processLeaks(state, Leaked, Ctx, Pred);
1357}
1358
George Karpenkov70c2ee32018-08-17 21:41:07 +00001359void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1360 CheckerContext &C) const {
1361 ExplodedNode *Pred = C.getPredecessor();
1362
1363 ProgramStateRef state = C.getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001364 SmallVector<SymbolRef, 10> Leaked;
1365
1366 // Update counts from autorelease pools
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001367 for (const auto &I: state->get<RefBindings>()) {
1368 SymbolRef Sym = I.first;
1369 if (SymReaper.isDead(Sym)) {
Artem Dergachev65b4d7d2018-10-15 17:47:56 +00001370 static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease");
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001371 const RefVal &V = I.second;
1372 state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001373 if (!state)
1374 return;
1375
1376 // Fetch the new reference count from the state, and use it to handle
1377 // this symbol.
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001378 state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001379 }
1380 }
1381
1382 if (Leaked.empty()) {
1383 C.addTransition(state);
1384 return;
1385 }
1386
1387 Pred = processLeaks(state, Leaked, C, Pred);
1388
1389 // Did we cache out?
1390 if (!Pred)
1391 return;
1392
1393 // Now generate a new node that nukes the old bindings.
1394 // The only bindings left at this point are the leaked symbols.
1395 RefBindingsTy::Factory &F = state->get_context<RefBindings>();
George Karpenkovf153cdf2019-01-16 23:21:15 +00001396 RefBindingsTy B = state->get<RefBindings>();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001397
George Karpenkovf153cdf2019-01-16 23:21:15 +00001398 for (SymbolRef L : Leaked)
1399 B = F.remove(B, L);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001400
1401 state = state->set<RefBindings>(B);
1402 C.addTransition(state, Pred);
1403}
1404
1405void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
1406 const char *NL, const char *Sep) const {
1407
1408 RefBindingsTy B = State->get<RefBindings>();
1409
1410 if (B.isEmpty())
1411 return;
1412
1413 Out << Sep << NL;
1414
George Karpenkov03391512019-01-16 23:21:38 +00001415 for (auto &I : B) {
1416 Out << I.first << " : ";
1417 I.second.print(Out);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001418 Out << NL;
1419 }
1420}
1421
1422//===----------------------------------------------------------------------===//
George Karpenkov70c2ee32018-08-17 21:41:07 +00001423// Checker registration.
1424//===----------------------------------------------------------------------===//
1425
1426void ento::registerRetainCountChecker(CheckerManager &Mgr) {
Kristof Umannc83b0dd2018-11-02 15:48:10 +00001427 auto *Chk = Mgr.registerChecker<RetainCountChecker>();
George Karpenkov27db3302018-12-07 20:21:51 +00001428 Chk->TrackObjCAndCFObjects = true;
1429}
Kristof Umannc83b0dd2018-11-02 15:48:10 +00001430
George Karpenkovd1081ec2018-12-11 01:13:58 +00001431// FIXME: remove this, hack for backwards compatibility:
1432// it should be possible to enable the NS/CF retain count checker as
1433// osx.cocoa.RetainCount, and it should be possible to disable
1434// osx.OSObjectRetainCount using osx.cocoa.RetainCount:CheckOSObject=false.
1435static bool hasPrevCheckOSObjectOptionDisabled(AnalyzerOptions &Options) {
1436 auto I = Options.Config.find("osx.cocoa.RetainCount:CheckOSObject");
1437 if (I != Options.Config.end())
1438 return I->getValue() == "false";
1439 return false;
1440}
1441
George Karpenkov27db3302018-12-07 20:21:51 +00001442void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
1443 auto *Chk = Mgr.registerChecker<RetainCountChecker>();
George Karpenkovd1081ec2018-12-11 01:13:58 +00001444 if (!hasPrevCheckOSObjectOptionDisabled(Mgr.getAnalyzerOptions()))
1445 Chk->TrackOSObjects = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001446}