blob: a72f09fb3ca4c5cb75fdb41a30b2bd7b57831074 [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.
George Karpenkov717c4c02019-01-10 18:15:17 +0000578 bool DeallocSent = false;
579
George Karpenkov70c2ee32018-08-17 21:41:07 +0000580 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
581 SVal V = CallOrMsg.getArgSVal(idx);
582
George Karpenkov9cbcc212019-01-10 18:14:12 +0000583 ArgEffect Effect = Summ.getArg(idx);
George Karpenkov5be959c2019-01-11 23:35:17 +0000584 if (SymbolRef Sym = V.getAsLocSymbol()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000585 if (const RefVal *T = getRefBinding(state, Sym)) {
George Karpenkov041c9fa2018-12-08 01:18:40 +0000586
George Karpenkov9cbcc212019-01-10 18:14:12 +0000587 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
588 Effect = ArgEffect(StopTrackingHard, ObjKind::OS);
George Karpenkov041c9fa2018-12-08 01:18:40 +0000589
George Karpenkov70c2ee32018-08-17 21:41:07 +0000590 state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
591 if (hasErr) {
592 ErrorRange = CallOrMsg.getArgSourceRange(idx);
593 ErrorSym = Sym;
594 break;
George Karpenkov717c4c02019-01-10 18:15:17 +0000595 } else if (Effect.getKind() == Dealloc) {
596 DeallocSent = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000597 }
598 }
599 }
600 }
601
George Karpenkovab0011e2018-08-23 00:26:59 +0000602 // Evaluate the effect on the message receiver / `this` argument.
George Karpenkov70c2ee32018-08-17 21:41:07 +0000603 bool ReceiverIsTracked = false;
604 if (!hasErr) {
George Karpenkovab0011e2018-08-23 00:26:59 +0000605 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000606 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
607 if (const RefVal *T = getRefBinding(state, Sym)) {
608 ReceiverIsTracked = true;
George Karpenkov585a2102019-01-10 18:13:59 +0000609 state = updateSymbol(state, Sym, *T,
George Karpenkov9cbcc212019-01-10 18:14:12 +0000610 Summ.getReceiverEffect(), hasErr, C);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000611 if (hasErr) {
612 ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
613 ErrorSym = Sym;
George Karpenkov717c4c02019-01-10 18:15:17 +0000614 } else if (Summ.getReceiverEffect().getKind() == Dealloc) {
615 DeallocSent = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000616 }
617 }
618 }
George Karpenkovab0011e2018-08-23 00:26:59 +0000619 } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
620 if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
621 if (const RefVal *T = getRefBinding(state, Sym)) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000622 state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
George Karpenkovab0011e2018-08-23 00:26:59 +0000623 hasErr, C);
624 if (hasErr) {
625 ErrorRange = MCall->getOriginExpr()->getSourceRange();
626 ErrorSym = Sym;
627 }
628 }
629 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000630 }
631 }
632
633 // Process any errors.
634 if (hasErr) {
635 processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
636 return;
637 }
638
639 // Consult the summary for the return value.
640 RetEffect RE = Summ.getRetEffect();
641
642 if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
643 if (ReceiverIsTracked)
644 RE = getSummaryManager(C).getObjAllocRetEffect();
645 else
646 RE = RetEffect::MakeNoRet();
647 }
648
George Karpenkov80c9e782018-08-22 01:16:49 +0000649 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
650 QualType ResultTy = CallOrMsg.getResultType();
651 if (RE.notOwned()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000652 const Expr *Ex = CallOrMsg.getOriginExpr();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000653 assert(Ex);
George Karpenkov80c9e782018-08-22 01:16:49 +0000654 ResultTy = GetReturnType(Ex, C.getASTContext());
George Karpenkov70c2ee32018-08-17 21:41:07 +0000655 }
George Karpenkov80c9e782018-08-22 01:16:49 +0000656 if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
657 state = setRefBinding(state, Sym, *updatedRefVal);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000658 }
659
George Karpenkov5be959c2019-01-11 23:35:17 +0000660 SmallVector<ProgramStateRef, 2> Out =
661 updateOutParameters(state, Summ, CallOrMsg);
662
663 for (ProgramStateRef St : Out) {
664 if (DeallocSent) {
665 C.addTransition(St, C.getPredecessor(), &DeallocSentTag);
666 } else {
667 C.addTransition(St);
668 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000669 }
670}
671
George Karpenkov585a2102019-01-10 18:13:59 +0000672ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
673 SymbolRef sym, RefVal V,
George Karpenkov9cbcc212019-01-10 18:14:12 +0000674 ArgEffect AE,
George Karpenkov585a2102019-01-10 18:13:59 +0000675 RefVal::Kind &hasErr,
676 CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000677 bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000678 if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) {
679 switch (AE.getKind()) {
680 default:
681 break;
682 case IncRef:
683 AE = AE.withKind(DoNothing);
684 break;
685 case DecRef:
686 AE = AE.withKind(DoNothing);
687 break;
688 case DecRefAndStopTrackingHard:
689 AE = AE.withKind(StopTracking);
690 break;
691 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000692 }
693
694 // Handle all use-after-releases.
695 if (V.getKind() == RefVal::Released) {
696 V = V ^ RefVal::ErrorUseAfterRelease;
697 hasErr = V.getKind();
698 return setRefBinding(state, sym, V);
699 }
700
George Karpenkov9cbcc212019-01-10 18:14:12 +0000701 switch (AE.getKind()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000702 case UnretainedOutParameter:
703 case RetainedOutParameter:
George Karpenkov5be959c2019-01-11 23:35:17 +0000704 case RetainedOutParameterOnZero:
705 case RetainedOutParameterOnNonZero:
George Karpenkov70c2ee32018-08-17 21:41:07 +0000706 llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
707 "not have ref state.");
708
George Karpenkov717c4c02019-01-10 18:15:17 +0000709 case Dealloc: // NB. we only need to add a note in a non-error case.
George Karpenkov70c2ee32018-08-17 21:41:07 +0000710 switch (V.getKind()) {
711 default:
712 llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
713 case RefVal::Owned:
714 // The object immediately transitions to the released state.
715 V = V ^ RefVal::Released;
716 V.clearCounts();
717 return setRefBinding(state, sym, V);
718 case RefVal::NotOwned:
719 V = V ^ RefVal::ErrorDeallocNotOwned;
720 hasErr = V.getKind();
721 break;
722 }
723 break;
724
725 case MayEscape:
726 if (V.getKind() == RefVal::Owned) {
727 V = V ^ RefVal::NotOwned;
728 break;
729 }
730
Reid Kleckner4dc0b1a2018-11-01 19:54:45 +0000731 LLVM_FALLTHROUGH;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000732
733 case DoNothing:
734 return state;
735
736 case Autorelease:
737 // Update the autorelease counts.
738 V = V.autorelease();
739 break;
740
741 case StopTracking:
742 case StopTrackingHard:
743 return removeRefBinding(state, sym);
744
745 case IncRef:
746 switch (V.getKind()) {
747 default:
748 llvm_unreachable("Invalid RefVal state for a retain.");
749 case RefVal::Owned:
750 case RefVal::NotOwned:
751 V = V + 1;
752 break;
753 }
754 break;
755
756 case DecRef:
757 case DecRefBridgedTransferred:
758 case DecRefAndStopTrackingHard:
759 switch (V.getKind()) {
760 default:
761 // case 'RefVal::Released' handled above.
762 llvm_unreachable("Invalid RefVal state for a release.");
763
764 case RefVal::Owned:
765 assert(V.getCount() > 0);
766 if (V.getCount() == 1) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000767 if (AE.getKind() == DecRefBridgedTransferred ||
George Karpenkov70c2ee32018-08-17 21:41:07 +0000768 V.getIvarAccessHistory() ==
769 RefVal::IvarAccessHistory::AccessedDirectly)
770 V = V ^ RefVal::NotOwned;
771 else
772 V = V ^ RefVal::Released;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000773 } else if (AE.getKind() == DecRefAndStopTrackingHard) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000774 return removeRefBinding(state, sym);
775 }
776
777 V = V - 1;
778 break;
779
780 case RefVal::NotOwned:
781 if (V.getCount() > 0) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000782 if (AE.getKind() == DecRefAndStopTrackingHard)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000783 return removeRefBinding(state, sym);
784 V = V - 1;
785 } else if (V.getIvarAccessHistory() ==
786 RefVal::IvarAccessHistory::AccessedDirectly) {
787 // Assume that the instance variable was holding on the object at
788 // +1, and we just didn't know.
George Karpenkov9cbcc212019-01-10 18:14:12 +0000789 if (AE.getKind() == DecRefAndStopTrackingHard)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000790 return removeRefBinding(state, sym);
791 V = V.releaseViaIvar() ^ RefVal::Released;
792 } else {
793 V = V ^ RefVal::ErrorReleaseNotOwned;
794 hasErr = V.getKind();
795 }
796 break;
797 }
798 break;
799 }
800 return setRefBinding(state, sym, V);
801}
802
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000803const RefCountBug &
804RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
805 SymbolRef Sym) const {
806 switch (ErrorKind) {
807 case RefVal::ErrorUseAfterRelease:
808 return useAfterRelease;
809 case RefVal::ErrorReleaseNotOwned:
810 return releaseNotOwned;
811 case RefVal::ErrorDeallocNotOwned:
812 if (Sym->getType()->getPointeeCXXRecordDecl())
813 return freeNotOwned;
814 return deallocNotOwned;
815 default:
816 llvm_unreachable("Unhandled error.");
817 }
818}
819
George Karpenkov70c2ee32018-08-17 21:41:07 +0000820void RetainCountChecker::processNonLeakError(ProgramStateRef St,
821 SourceRange ErrorRange,
822 RefVal::Kind ErrorKind,
823 SymbolRef Sym,
824 CheckerContext &C) const {
825 // HACK: Ignore retain-count issues on values accessed through ivars,
826 // because of cases like this:
827 // [_contentView retain];
828 // [_contentView removeFromSuperview];
829 // [self addSubview:_contentView]; // invalidates 'self'
830 // [_contentView release];
831 if (const RefVal *RV = getRefBinding(St, Sym))
832 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
833 return;
834
835 ExplodedNode *N = C.generateErrorNode(St);
836 if (!N)
837 return;
838
George Karpenkov0bb17c42019-01-10 18:16:25 +0000839 auto report = llvm::make_unique<RefCountReport>(
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000840 errorKindToBugKind(ErrorKind, Sym),
841 C.getASTContext().getLangOpts(), N, Sym);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000842 report->addRange(ErrorRange);
843 C.emitReport(std::move(report));
844}
845
846//===----------------------------------------------------------------------===//
847// Handle the return values of retain-count-related functions.
848//===----------------------------------------------------------------------===//
849
850bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000851 ProgramStateRef state = C.getState();
852 const FunctionDecl *FD = C.getCalleeDecl(CE);
853 if (!FD)
854 return false;
855
George Karpenkovc4d6b932018-08-17 21:42:05 +0000856 RetainSummaryManager &SmrMgr = getSummaryManager(C);
857 QualType ResultTy = CE->getCallReturnType(C.getASTContext());
George Karpenkov70c2ee32018-08-17 21:41:07 +0000858
George Karpenkov70c2ee32018-08-17 21:41:07 +0000859 // See if the function has 'rc_ownership_trusted_implementation'
860 // annotate attribute. If it does, we will not inline it.
861 bool hasTrustedImplementationAnnotation = false;
862
George Karpenkov41dc8de2018-10-11 22:59:16 +0000863 const LocationContext *LCtx = C.getLocationContext();
864
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000865 using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
866 Optional<BehaviorSummary> BSmr =
867 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
868
George Karpenkovc4d6b932018-08-17 21:42:05 +0000869 // See if it's one of the specific functions we know how to eval.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000870 if (!BSmr)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000871 return false;
872
873 // Bind the return value.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000874 if (BSmr == BehaviorSummary::Identity ||
George Karpenkovdb0c66e2019-01-22 19:50:47 +0000875 BSmr == BehaviorSummary::IdentityOrZero ||
876 BSmr == BehaviorSummary::IdentityThis) {
877
878 const Expr *BindReturnTo =
879 (BSmr == BehaviorSummary::IdentityThis)
880 ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
881 : CE->getArg(0);
882 SVal RetVal = state->getSVal(BindReturnTo, LCtx);
George Karpenkov48de5822018-10-23 23:11:30 +0000883
George Karpenkov70c2ee32018-08-17 21:41:07 +0000884 // If the receiver is unknown or the function has
885 // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
886 // return value.
George Karpenkovdb0c66e2019-01-22 19:50:47 +0000887 // FIXME: this branch is very strange.
George Karpenkov48de5822018-10-23 23:11:30 +0000888 if (RetVal.isUnknown() ||
889 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
890 SValBuilder &SVB = C.getSValBuilder();
891 RetVal =
892 SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
893 }
George Karpenkovdb0c66e2019-01-22 19:50:47 +0000894
895 // Bind the value.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000896 state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
897
898 if (BSmr == BehaviorSummary::IdentityOrZero) {
899 // Add a branch where the output is zero.
900 ProgramStateRef NullOutputState = C.getState();
901
902 // Assume that output is zero on the other branch.
903 NullOutputState = NullOutputState->BindExpr(
904 CE, LCtx, C.getSValBuilder().makeNull(), /*Invalidate=*/false);
George Karpenkova9e29562019-01-22 19:51:00 +0000905 C.addTransition(NullOutputState, &CastFailTag);
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000906
907 // And on the original branch assume that both input and
908 // output are non-zero.
909 if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
910 state = state->assume(*L, /*Assumption=*/true);
911
912 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000913 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000914
George Karpenkov70c2ee32018-08-17 21:41:07 +0000915 C.addTransition(state);
916 return true;
917}
918
George Karpenkov04553e52018-09-21 20:37:20 +0000919ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
920 CheckerContext &C) const {
921 ExplodedNode *Pred = C.getPredecessor();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000922
923 // Only adjust the reference count if this is the top-level call frame,
924 // and not the result of inlining. In the future, we should do
925 // better checking even for inlined calls, and see if they match
926 // with their expected semantics (e.g., the method should return a retained
927 // object, etc.).
928 if (!C.inTopFrame())
George Karpenkov04553e52018-09-21 20:37:20 +0000929 return Pred;
930
931 if (!S)
932 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000933
934 const Expr *RetE = S->getRetValue();
935 if (!RetE)
George Karpenkov04553e52018-09-21 20:37:20 +0000936 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000937
938 ProgramStateRef state = C.getState();
939 SymbolRef Sym =
940 state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol();
941 if (!Sym)
George Karpenkov04553e52018-09-21 20:37:20 +0000942 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000943
944 // Get the reference count binding (if any).
945 const RefVal *T = getRefBinding(state, Sym);
946 if (!T)
George Karpenkov04553e52018-09-21 20:37:20 +0000947 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000948
949 // Change the reference count.
950 RefVal X = *T;
951
952 switch (X.getKind()) {
953 case RefVal::Owned: {
954 unsigned cnt = X.getCount();
955 assert(cnt > 0);
956 X.setCount(cnt - 1);
957 X = X ^ RefVal::ReturnedOwned;
958 break;
959 }
960
961 case RefVal::NotOwned: {
962 unsigned cnt = X.getCount();
963 if (cnt) {
964 X.setCount(cnt - 1);
965 X = X ^ RefVal::ReturnedOwned;
George Karpenkov04553e52018-09-21 20:37:20 +0000966 } else {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000967 X = X ^ RefVal::ReturnedNotOwned;
968 }
969 break;
970 }
971
972 default:
George Karpenkov04553e52018-09-21 20:37:20 +0000973 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000974 }
975
976 // Update the binding.
977 state = setRefBinding(state, Sym, X);
George Karpenkov04553e52018-09-21 20:37:20 +0000978 Pred = C.addTransition(state);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000979
980 // At this point we have updated the state properly.
981 // Everything after this is merely checking to see if the return value has
982 // been over- or under-retained.
983
984 // Did we cache out?
985 if (!Pred)
George Karpenkov04553e52018-09-21 20:37:20 +0000986 return nullptr;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000987
988 // Update the autorelease counts.
989 static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease");
George Karpenkov04553e52018-09-21 20:37:20 +0000990 state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000991
George Karpenkov04553e52018-09-21 20:37:20 +0000992 // Have we generated a sink node?
George Karpenkov70c2ee32018-08-17 21:41:07 +0000993 if (!state)
George Karpenkov04553e52018-09-21 20:37:20 +0000994 return nullptr;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000995
996 // Get the updated binding.
997 T = getRefBinding(state, Sym);
998 assert(T);
999 X = *T;
1000
1001 // Consult the summary of the enclosing method.
1002 RetainSummaryManager &Summaries = getSummaryManager(C);
1003 const Decl *CD = &Pred->getCodeDecl();
1004 RetEffect RE = RetEffect::MakeNoRet();
1005
1006 // FIXME: What is the convention for blocks? Is there one?
1007 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
1008 const RetainSummary *Summ = Summaries.getMethodSummary(MD);
1009 RE = Summ->getRetEffect();
1010 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
1011 if (!isa<CXXMethodDecl>(FD)) {
1012 const RetainSummary *Summ = Summaries.getFunctionSummary(FD);
1013 RE = Summ->getRetEffect();
1014 }
1015 }
1016
George Karpenkov04553e52018-09-21 20:37:20 +00001017 return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001018}
1019
George Karpenkov04553e52018-09-21 20:37:20 +00001020ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
George Karpenkov70c2ee32018-08-17 21:41:07 +00001021 CheckerContext &C,
1022 ExplodedNode *Pred,
1023 RetEffect RE, RefVal X,
1024 SymbolRef Sym,
1025 ProgramStateRef state) const {
1026 // HACK: Ignore retain-count issues on values accessed through ivars,
1027 // because of cases like this:
1028 // [_contentView retain];
1029 // [_contentView removeFromSuperview];
1030 // [self addSubview:_contentView]; // invalidates 'self'
1031 // [_contentView release];
1032 if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
George Karpenkov04553e52018-09-21 20:37:20 +00001033 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001034
1035 // Any leaks or other errors?
1036 if (X.isReturnedOwned() && X.getCount() == 0) {
1037 if (RE.getKind() != RetEffect::NoRet) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001038 if (!RE.isOwned()) {
George Karpenkov04553e52018-09-21 20:37:20 +00001039
George Karpenkov70c2ee32018-08-17 21:41:07 +00001040 // The returning type is a CF, we expect the enclosing method should
1041 // return ownership.
George Karpenkov70c2ee32018-08-17 21:41:07 +00001042 X = X ^ RefVal::ErrorLeakReturned;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001043
George Karpenkov70c2ee32018-08-17 21:41:07 +00001044 // Generate an error node.
1045 state = setRefBinding(state, Sym, X);
1046
1047 static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak");
1048 ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
1049 if (N) {
1050 const LangOptions &LOpts = C.getASTContext().getLangOpts();
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001051 auto R =
1052 llvm::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C);
George Karpenkov04553e52018-09-21 20:37:20 +00001053 C.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001054 }
George Karpenkov04553e52018-09-21 20:37:20 +00001055 return N;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001056 }
1057 }
1058 } else if (X.isReturnedNotOwned()) {
1059 if (RE.isOwned()) {
1060 if (X.getIvarAccessHistory() ==
1061 RefVal::IvarAccessHistory::AccessedDirectly) {
1062 // Assume the method was trying to transfer a +1 reference from a
1063 // strong ivar to the caller.
1064 state = setRefBinding(state, Sym,
1065 X.releaseViaIvar() ^ RefVal::ReturnedOwned);
1066 } else {
1067 // Trying to return a not owned object to a caller expecting an
1068 // owned object.
1069 state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
1070
1071 static CheckerProgramPointTag
1072 ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned");
1073
1074 ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
1075 if (N) {
George Karpenkov0bb17c42019-01-10 18:16:25 +00001076 auto R = llvm::make_unique<RefCountReport>(
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001077 returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
George Karpenkov04553e52018-09-21 20:37:20 +00001078 C.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001079 }
George Karpenkov04553e52018-09-21 20:37:20 +00001080 return N;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001081 }
1082 }
1083 }
George Karpenkov04553e52018-09-21 20:37:20 +00001084 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001085}
1086
1087//===----------------------------------------------------------------------===//
1088// Check various ways a symbol can be invalidated.
1089//===----------------------------------------------------------------------===//
1090
1091void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
1092 CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001093 ProgramStateRef state = C.getState();
George Karpenkov03391512019-01-16 23:21:38 +00001094 const MemRegion *MR = loc.getAsRegion();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001095
George Karpenkov03391512019-01-16 23:21:38 +00001096 // Find all symbols referenced by 'val' that we are tracking
George Karpenkov70c2ee32018-08-17 21:41:07 +00001097 // and stop tracking them.
George Karpenkov03391512019-01-16 23:21:38 +00001098 if (MR && shouldEscapeRegion(MR)) {
1099 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
1100 C.addTransition(state);
1101 }
George Karpenkov70c2ee32018-08-17 21:41:07 +00001102}
1103
1104ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
George Karpenkov6e9fd132018-08-22 01:17:09 +00001105 SVal Cond,
1106 bool Assumption) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001107 // FIXME: We may add to the interface of evalAssume the list of symbols
1108 // whose assumptions have changed. For now we just iterate through the
1109 // bindings and check if any of the tracked symbols are NULL. This isn't
1110 // too bad since the number of symbols we will track in practice are
1111 // probably small and evalAssume is only called at branches and a few
1112 // other places.
1113 RefBindingsTy B = state->get<RefBindings>();
1114
1115 if (B.isEmpty())
1116 return state;
1117
1118 bool changed = false;
1119 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
George Karpenkov03391512019-01-16 23:21:38 +00001120 ConstraintManager &CMgr = state->getConstraintManager();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001121
George Karpenkov03391512019-01-16 23:21:38 +00001122 for (auto &I : B) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001123 // Check if the symbol is null stop tracking the symbol.
George Karpenkov03391512019-01-16 23:21:38 +00001124 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001125 if (AllocFailed.isConstrainedTrue()) {
1126 changed = true;
George Karpenkov03391512019-01-16 23:21:38 +00001127 B = RefBFactory.remove(B, I.first);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001128 }
1129 }
1130
1131 if (changed)
1132 state = state->set<RefBindings>(B);
1133
1134 return state;
1135}
1136
George Karpenkovf153cdf2019-01-16 23:21:15 +00001137ProgramStateRef RetainCountChecker::checkRegionChanges(
1138 ProgramStateRef state, const InvalidatedSymbols *invalidated,
1139 ArrayRef<const MemRegion *> ExplicitRegions,
1140 ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
1141 const CallEvent *Call) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001142 if (!invalidated)
1143 return state;
1144
1145 llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001146
George Karpenkovf153cdf2019-01-16 23:21:15 +00001147 for (const MemRegion *I : ExplicitRegions)
1148 if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
1149 WhitelistedSymbols.insert(SR->getSymbol());
1150
1151 for (SymbolRef sym : *invalidated) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001152 if (WhitelistedSymbols.count(sym))
1153 continue;
1154 // Remove any existing reference-count binding.
1155 state = removeRefBinding(state, sym);
1156 }
1157 return state;
1158}
1159
George Karpenkov70c2ee32018-08-17 21:41:07 +00001160ProgramStateRef
1161RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
1162 ExplodedNode *Pred,
1163 const ProgramPointTag *Tag,
1164 CheckerContext &Ctx,
George Karpenkov04553e52018-09-21 20:37:20 +00001165 SymbolRef Sym,
1166 RefVal V,
1167 const ReturnStmt *S) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001168 unsigned ACnt = V.getAutoreleaseCount();
1169
1170 // No autorelease counts? Nothing to be done.
1171 if (!ACnt)
1172 return state;
1173
1174 unsigned Cnt = V.getCount();
1175
1176 // FIXME: Handle sending 'autorelease' to already released object.
1177
1178 if (V.getKind() == RefVal::ReturnedOwned)
1179 ++Cnt;
1180
1181 // If we would over-release here, but we know the value came from an ivar,
1182 // assume it was a strong ivar that's just been relinquished.
1183 if (ACnt > Cnt &&
1184 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
1185 V = V.releaseViaIvar();
1186 --ACnt;
1187 }
1188
1189 if (ACnt <= Cnt) {
1190 if (ACnt == Cnt) {
1191 V.clearCounts();
George Karpenkov04553e52018-09-21 20:37:20 +00001192 if (V.getKind() == RefVal::ReturnedOwned) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001193 V = V ^ RefVal::ReturnedNotOwned;
George Karpenkov04553e52018-09-21 20:37:20 +00001194 } else {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001195 V = V ^ RefVal::NotOwned;
George Karpenkov04553e52018-09-21 20:37:20 +00001196 }
George Karpenkov70c2ee32018-08-17 21:41:07 +00001197 } else {
1198 V.setCount(V.getCount() - ACnt);
1199 V.setAutoreleaseCount(0);
1200 }
1201 return setRefBinding(state, Sym, V);
1202 }
1203
1204 // HACK: Ignore retain-count issues on values accessed through ivars,
1205 // because of cases like this:
1206 // [_contentView retain];
1207 // [_contentView removeFromSuperview];
1208 // [self addSubview:_contentView]; // invalidates 'self'
1209 // [_contentView release];
1210 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1211 return state;
1212
1213 // Woah! More autorelease counts then retain counts left.
1214 // Emit hard error.
1215 V = V ^ RefVal::ErrorOverAutorelease;
1216 state = setRefBinding(state, Sym, V);
1217
1218 ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
1219 if (N) {
1220 SmallString<128> sbuf;
1221 llvm::raw_svector_ostream os(sbuf);
1222 os << "Object was autoreleased ";
1223 if (V.getAutoreleaseCount() > 1)
1224 os << V.getAutoreleaseCount() << " times but the object ";
1225 else
1226 os << "but ";
1227 os << "has a +" << V.getCount() << " retain count";
1228
George Karpenkov70c2ee32018-08-17 21:41:07 +00001229 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001230 auto R = llvm::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym,
1231 os.str());
George Karpenkov04553e52018-09-21 20:37:20 +00001232 Ctx.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001233 }
1234
1235 return nullptr;
1236}
1237
1238ProgramStateRef
1239RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
1240 SymbolRef sid, RefVal V,
1241 SmallVectorImpl<SymbolRef> &Leaked) const {
1242 bool hasLeak;
1243
1244 // HACK: Ignore retain-count issues on values accessed through ivars,
1245 // because of cases like this:
1246 // [_contentView retain];
1247 // [_contentView removeFromSuperview];
1248 // [self addSubview:_contentView]; // invalidates 'self'
1249 // [_contentView release];
1250 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1251 hasLeak = false;
1252 else if (V.isOwned())
1253 hasLeak = true;
1254 else if (V.isNotOwned() || V.isReturnedOwned())
1255 hasLeak = (V.getCount() > 0);
1256 else
1257 hasLeak = false;
1258
1259 if (!hasLeak)
1260 return removeRefBinding(state, sid);
1261
1262 Leaked.push_back(sid);
1263 return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
1264}
1265
1266ExplodedNode *
1267RetainCountChecker::processLeaks(ProgramStateRef state,
1268 SmallVectorImpl<SymbolRef> &Leaked,
1269 CheckerContext &Ctx,
1270 ExplodedNode *Pred) const {
1271 // Generate an intermediate node representing the leak point.
1272 ExplodedNode *N = Ctx.addTransition(state, Pred);
George Karpenkovf153cdf2019-01-16 23:21:15 +00001273 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001274
1275 if (N) {
George Karpenkovf153cdf2019-01-16 23:21:15 +00001276 for (SymbolRef L : Leaked) {
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001277 const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn;
1278 Ctx.emitReport(llvm::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001279 }
1280 }
1281
1282 return N;
1283}
1284
George Karpenkovb1b791b2018-08-17 21:43:27 +00001285static bool isISLObjectRef(QualType Ty) {
1286 return StringRef(Ty.getAsString()).startswith("isl_");
George Karpenkov70c2ee32018-08-17 21:41:07 +00001287}
1288
1289void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
1290 if (!Ctx.inTopFrame())
1291 return;
1292
George Karpenkovc4d6b932018-08-17 21:42:05 +00001293 RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001294 const LocationContext *LCtx = Ctx.getLocationContext();
1295 const FunctionDecl *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
1296
George Karpenkovc4d6b932018-08-17 21:42:05 +00001297 if (!FD || SmrMgr.isTrustedReferenceCountImplementation(FD))
George Karpenkov70c2ee32018-08-17 21:41:07 +00001298 return;
1299
1300 ProgramStateRef state = Ctx.getState();
George Karpenkovc4d6b932018-08-17 21:42:05 +00001301 const RetainSummary *FunctionSummary = SmrMgr.getFunctionSummary(FD);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001302 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
1303
1304 for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) {
1305 const ParmVarDecl *Param = FD->getParamDecl(idx);
1306 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
1307
1308 QualType Ty = Param->getType();
1309 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
George Karpenkov585a2102019-01-10 18:13:59 +00001310 if (AE && AE->getKind() == DecRef && isISLObjectRef(Ty)) {
George Karpenkov6e9fd132018-08-22 01:17:09 +00001311 state = setRefBinding(
George Karpenkov7e3016d2019-01-10 18:13:46 +00001312 state, Sym, RefVal::makeOwned(ObjKind::Generalized, Ty));
George Karpenkovb1b791b2018-08-17 21:43:27 +00001313 } else if (isISLObjectRef(Ty)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001314 state = setRefBinding(
1315 state, Sym,
George Karpenkov7e3016d2019-01-10 18:13:46 +00001316 RefVal::makeNotOwned(ObjKind::Generalized, Ty));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001317 }
1318 }
1319
1320 Ctx.addTransition(state);
1321}
1322
1323void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
1324 CheckerContext &Ctx) const {
George Karpenkov04553e52018-09-21 20:37:20 +00001325 ExplodedNode *Pred = processReturn(RS, Ctx);
1326
1327 // Created state cached out.
1328 if (!Pred) {
1329 return;
1330 }
1331
1332 ProgramStateRef state = Pred->getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001333 RefBindingsTy B = state->get<RefBindings>();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001334
1335 // Don't process anything within synthesized bodies.
1336 const LocationContext *LCtx = Pred->getLocationContext();
1337 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
1338 assert(!LCtx->inTopFrame());
1339 return;
1340 }
1341
George Karpenkov03391512019-01-16 23:21:38 +00001342 for (auto &I : B) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001343 state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx,
George Karpenkov03391512019-01-16 23:21:38 +00001344 I.first, I.second);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001345 if (!state)
1346 return;
1347 }
1348
1349 // If the current LocationContext has a parent, don't check for leaks.
1350 // We will do that later.
1351 // FIXME: we should instead check for imbalances of the retain/releases,
1352 // and suggest annotations.
1353 if (LCtx->getParent())
1354 return;
1355
1356 B = state->get<RefBindings>();
1357 SmallVector<SymbolRef, 10> Leaked;
1358
George Karpenkov03391512019-01-16 23:21:38 +00001359 for (auto &I : B)
1360 state = handleSymbolDeath(state, I.first, I.second, Leaked);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001361
1362 processLeaks(state, Leaked, Ctx, Pred);
1363}
1364
George Karpenkov70c2ee32018-08-17 21:41:07 +00001365void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1366 CheckerContext &C) const {
1367 ExplodedNode *Pred = C.getPredecessor();
1368
1369 ProgramStateRef state = C.getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001370 SmallVector<SymbolRef, 10> Leaked;
1371
1372 // Update counts from autorelease pools
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001373 for (const auto &I: state->get<RefBindings>()) {
1374 SymbolRef Sym = I.first;
1375 if (SymReaper.isDead(Sym)) {
Artem Dergachev65b4d7d2018-10-15 17:47:56 +00001376 static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease");
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001377 const RefVal &V = I.second;
1378 state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001379 if (!state)
1380 return;
1381
1382 // Fetch the new reference count from the state, and use it to handle
1383 // this symbol.
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001384 state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001385 }
1386 }
1387
1388 if (Leaked.empty()) {
1389 C.addTransition(state);
1390 return;
1391 }
1392
1393 Pred = processLeaks(state, Leaked, C, Pred);
1394
1395 // Did we cache out?
1396 if (!Pred)
1397 return;
1398
1399 // Now generate a new node that nukes the old bindings.
1400 // The only bindings left at this point are the leaked symbols.
1401 RefBindingsTy::Factory &F = state->get_context<RefBindings>();
George Karpenkovf153cdf2019-01-16 23:21:15 +00001402 RefBindingsTy B = state->get<RefBindings>();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001403
George Karpenkovf153cdf2019-01-16 23:21:15 +00001404 for (SymbolRef L : Leaked)
1405 B = F.remove(B, L);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001406
1407 state = state->set<RefBindings>(B);
1408 C.addTransition(state, Pred);
1409}
1410
1411void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
1412 const char *NL, const char *Sep) const {
1413
1414 RefBindingsTy B = State->get<RefBindings>();
1415
1416 if (B.isEmpty())
1417 return;
1418
1419 Out << Sep << NL;
1420
George Karpenkov03391512019-01-16 23:21:38 +00001421 for (auto &I : B) {
1422 Out << I.first << " : ";
1423 I.second.print(Out);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001424 Out << NL;
1425 }
1426}
1427
1428//===----------------------------------------------------------------------===//
George Karpenkov70c2ee32018-08-17 21:41:07 +00001429// Checker registration.
1430//===----------------------------------------------------------------------===//
1431
1432void ento::registerRetainCountChecker(CheckerManager &Mgr) {
Kristof Umannc83b0dd2018-11-02 15:48:10 +00001433 auto *Chk = Mgr.registerChecker<RetainCountChecker>();
George Karpenkov27db3302018-12-07 20:21:51 +00001434 Chk->TrackObjCAndCFObjects = true;
1435}
Kristof Umannc83b0dd2018-11-02 15:48:10 +00001436
George Karpenkovd1081ec2018-12-11 01:13:58 +00001437// FIXME: remove this, hack for backwards compatibility:
1438// it should be possible to enable the NS/CF retain count checker as
1439// osx.cocoa.RetainCount, and it should be possible to disable
1440// osx.OSObjectRetainCount using osx.cocoa.RetainCount:CheckOSObject=false.
1441static bool hasPrevCheckOSObjectOptionDisabled(AnalyzerOptions &Options) {
1442 auto I = Options.Config.find("osx.cocoa.RetainCount:CheckOSObject");
1443 if (I != Options.Config.end())
1444 return I->getValue() == "false";
1445 return false;
1446}
1447
George Karpenkov27db3302018-12-07 20:21:51 +00001448void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
1449 auto *Chk = Mgr.registerChecker<RetainCountChecker>();
George Karpenkovd1081ec2018-12-11 01:13:58 +00001450 if (!hasPrevCheckOSObjectOptionDisabled(Mgr.getAnalyzerOptions()))
1451 Chk->TrackOSObjects = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001452}