blob: c3d191429e4a259ac4987cdea3efdf43e6617d96 [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"
George Karpenkov6fdd2bd2019-01-25 01:24:04 +000015#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
George Karpenkov70c2ee32018-08-17 21:41:07 +000016
17using namespace clang;
18using namespace ento;
George Karpenkov70c2ee32018-08-17 21:41:07 +000019using namespace retaincountchecker;
20using llvm::StrInStrNoCase;
21
22REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
23
24namespace clang {
25namespace ento {
26namespace retaincountchecker {
27
28const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) {
29 return State->get<RefBindings>(Sym);
30}
31
George Karpenkov2c2d0b62019-01-18 19:24:55 +000032} // end namespace retaincountchecker
33} // end namespace ento
34} // end namespace clang
35
George Karpenkovf153cdf2019-01-16 23:21:15 +000036static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym,
George Karpenkov70c2ee32018-08-17 21:41:07 +000037 RefVal Val) {
George Karpenkovd5ef0d22018-08-29 20:28:33 +000038 assert(Sym != nullptr);
George Karpenkov70c2ee32018-08-17 21:41:07 +000039 return State->set<RefBindings>(Sym, Val);
40}
41
George Karpenkovf153cdf2019-01-16 23:21:15 +000042static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) {
George Karpenkov70c2ee32018-08-17 21:41:07 +000043 return State->remove<RefBindings>(Sym);
44}
45
George Karpenkov70c2ee32018-08-17 21:41:07 +000046void RefVal::print(raw_ostream &Out) const {
47 if (!T.isNull())
George Karpenkov081c4772018-10-23 23:11:50 +000048 Out << "Tracked " << T.getAsString() << " | ";
George Karpenkov70c2ee32018-08-17 21:41:07 +000049
50 switch (getKind()) {
51 default: llvm_unreachable("Invalid RefVal kind");
52 case Owned: {
53 Out << "Owned";
54 unsigned cnt = getCount();
55 if (cnt) Out << " (+ " << cnt << ")";
56 break;
57 }
58
59 case NotOwned: {
60 Out << "NotOwned";
61 unsigned cnt = getCount();
62 if (cnt) Out << " (+ " << cnt << ")";
63 break;
64 }
65
66 case ReturnedOwned: {
67 Out << "ReturnedOwned";
68 unsigned cnt = getCount();
69 if (cnt) Out << " (+ " << cnt << ")";
70 break;
71 }
72
73 case ReturnedNotOwned: {
74 Out << "ReturnedNotOwned";
75 unsigned cnt = getCount();
76 if (cnt) Out << " (+ " << cnt << ")";
77 break;
78 }
79
80 case Released:
81 Out << "Released";
82 break;
83
84 case ErrorDeallocNotOwned:
85 Out << "-dealloc (not-owned)";
86 break;
87
88 case ErrorLeak:
89 Out << "Leaked";
90 break;
91
92 case ErrorLeakReturned:
93 Out << "Leaked (Bad naming)";
94 break;
95
96 case ErrorUseAfterRelease:
97 Out << "Use-After-Release [ERROR]";
98 break;
99
100 case ErrorReleaseNotOwned:
101 Out << "Release of Not-Owned [ERROR]";
102 break;
103
104 case RefVal::ErrorOverAutorelease:
105 Out << "Over-autoreleased";
106 break;
107
108 case RefVal::ErrorReturnedNotOwned:
109 Out << "Non-owned object returned instead of owned";
110 break;
111 }
112
113 switch (getIvarAccessHistory()) {
114 case IvarAccessHistory::None:
115 break;
116 case IvarAccessHistory::AccessedDirectly:
117 Out << " [direct ivar access]";
118 break;
119 case IvarAccessHistory::ReleasedAfterDirectAccess:
120 Out << " [released after direct ivar access]";
121 }
122
123 if (ACnt) {
124 Out << " [autorelease -" << ACnt << ']';
125 }
126}
127
128namespace {
129class StopTrackingCallback final : public SymbolVisitor {
130 ProgramStateRef state;
131public:
132 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
133 ProgramStateRef getState() const { return state; }
134
135 bool VisitSymbol(SymbolRef sym) override {
George Karpenkovf153cdf2019-01-16 23:21:15 +0000136 state = removeRefBinding(state, sym);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000137 return true;
138 }
139};
140} // end anonymous namespace
141
142//===----------------------------------------------------------------------===//
143// Handle statements that may have an effect on refcounts.
144//===----------------------------------------------------------------------===//
145
146void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
147 CheckerContext &C) const {
148
149 // Scan the BlockDecRefExprs for any object the retain count checker
150 // may be tracking.
151 if (!BE->getBlockDecl()->hasCaptures())
152 return;
153
154 ProgramStateRef state = C.getState();
155 auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
156
157 BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
158 E = R->referenced_vars_end();
159
160 if (I == E)
161 return;
162
163 // FIXME: For now we invalidate the tracking of all symbols passed to blocks
164 // via captured variables, even though captured variables result in a copy
165 // and in implicit increment/decrement of a retain count.
166 SmallVector<const MemRegion*, 10> Regions;
167 const LocationContext *LC = C.getLocationContext();
168 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
169
170 for ( ; I != E; ++I) {
171 const VarRegion *VR = I.getCapturedRegion();
172 if (VR->getSuperRegion() == R) {
173 VR = MemMgr.getVarRegion(VR->getDecl(), LC);
174 }
175 Regions.push_back(VR);
176 }
177
George Karpenkovd3e76752018-10-23 23:12:12 +0000178 state = state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000179 C.addTransition(state);
180}
181
182void RetainCountChecker::checkPostStmt(const CastExpr *CE,
183 CheckerContext &C) const {
184 const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
185 if (!BE)
186 return;
187
George Karpenkov9cbcc212019-01-10 18:14:12 +0000188 ArgEffect AE = ArgEffect(IncRef, ObjKind::ObjC);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000189
190 switch (BE->getBridgeKind()) {
191 case OBC_Bridge:
192 // Do nothing.
193 return;
194 case OBC_BridgeRetained:
George Karpenkov9cbcc212019-01-10 18:14:12 +0000195 AE = AE.withKind(IncRef);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000196 break;
197 case OBC_BridgeTransfer:
George Karpenkov9cbcc212019-01-10 18:14:12 +0000198 AE = AE.withKind(DecRefBridgedTransferred);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000199 break;
200 }
201
202 ProgramStateRef state = C.getState();
203 SymbolRef Sym = C.getSVal(CE).getAsLocSymbol();
204 if (!Sym)
205 return;
206 const RefVal* T = getRefBinding(state, Sym);
207 if (!T)
208 return;
209
210 RefVal::Kind hasErr = (RefVal::Kind) 0;
211 state = updateSymbol(state, Sym, *T, AE, hasErr, C);
212
213 if (hasErr) {
214 // FIXME: If we get an error during a bridge cast, should we report it?
215 return;
216 }
217
218 C.addTransition(state);
219}
220
221void RetainCountChecker::processObjCLiterals(CheckerContext &C,
222 const Expr *Ex) const {
223 ProgramStateRef state = C.getState();
224 const ExplodedNode *pred = C.getPredecessor();
225 for (const Stmt *Child : Ex->children()) {
226 SVal V = pred->getSVal(Child);
227 if (SymbolRef sym = V.getAsSymbol())
228 if (const RefVal* T = getRefBinding(state, sym)) {
229 RefVal::Kind hasErr = (RefVal::Kind) 0;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000230 state = updateSymbol(state, sym, *T,
231 ArgEffect(MayEscape, ObjKind::ObjC), hasErr, C);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000232 if (hasErr) {
233 processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C);
234 return;
235 }
236 }
237 }
238
239 // Return the object as autoreleased.
George Karpenkov7e3016d2019-01-10 18:13:46 +0000240 // RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000241 if (SymbolRef sym =
242 state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
243 QualType ResultTy = Ex->getType();
244 state = setRefBinding(state, sym,
George Karpenkov7e3016d2019-01-10 18:13:46 +0000245 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
George Karpenkov70c2ee32018-08-17 21:41:07 +0000246 }
247
248 C.addTransition(state);
249}
250
251void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
252 CheckerContext &C) const {
253 // Apply the 'MayEscape' to all values.
254 processObjCLiterals(C, AL);
255}
256
257void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
258 CheckerContext &C) const {
259 // Apply the 'MayEscape' to all keys and values.
260 processObjCLiterals(C, DL);
261}
262
263void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
264 CheckerContext &C) const {
265 const ExplodedNode *Pred = C.getPredecessor();
266 ProgramStateRef State = Pred->getState();
267
268 if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) {
269 QualType ResultTy = Ex->getType();
270 State = setRefBinding(State, Sym,
George Karpenkov7e3016d2019-01-10 18:13:46 +0000271 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
George Karpenkov70c2ee32018-08-17 21:41:07 +0000272 }
273
274 C.addTransition(State);
275}
276
277void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
278 CheckerContext &C) const {
279 Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
280 if (!IVarLoc)
281 return;
282
283 ProgramStateRef State = C.getState();
284 SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
285 if (!Sym || !dyn_cast_or_null<ObjCIvarRegion>(Sym->getOriginRegion()))
286 return;
287
288 // Accessing an ivar directly is unusual. If we've done that, be more
289 // forgiving about what the surrounding code is allowed to do.
290
291 QualType Ty = Sym->getType();
George Karpenkov7e3016d2019-01-10 18:13:46 +0000292 ObjKind Kind;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000293 if (Ty->isObjCRetainableType())
George Karpenkov7e3016d2019-01-10 18:13:46 +0000294 Kind = ObjKind::ObjC;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000295 else if (coreFoundation::isCFObjectRef(Ty))
George Karpenkov7e3016d2019-01-10 18:13:46 +0000296 Kind = ObjKind::CF;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000297 else
298 return;
299
300 // If the value is already known to be nil, don't bother tracking it.
301 ConstraintManager &CMgr = State->getConstraintManager();
302 if (CMgr.isNull(State, Sym).isConstrainedTrue())
303 return;
304
305 if (const RefVal *RV = getRefBinding(State, Sym)) {
306 // If we've seen this symbol before, or we're only seeing it now because
307 // of something the analyzer has synthesized, don't do anything.
308 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None ||
309 isSynthesizedAccessor(C.getStackFrame())) {
310 return;
311 }
312
313 // Note that this value has been loaded from an ivar.
314 C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
315 return;
316 }
317
318 RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty);
319
320 // In a synthesized accessor, the effective retain count is +0.
321 if (isSynthesizedAccessor(C.getStackFrame())) {
322 C.addTransition(setRefBinding(State, Sym, PlusZero));
323 return;
324 }
325
326 State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
327 C.addTransition(State);
328}
329
George Karpenkov6fdd2bd2019-01-25 01:24:04 +0000330static bool isReceiverUnconsumedSelf(const CallEvent &Call) {
331 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
332
333 // Check if the message is not consumed, we know it will not be used in
334 // an assignment, ex: "self = [super init]".
335 return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
336 !Call.getLocationContext()
337 ->getAnalysisDeclContext()
338 ->getParentMap()
339 .isConsumedExpr(Call.getOriginExpr());
340 }
341 return false;
342}
343
344const static RetainSummary *getSummary(RetainSummaryManager &Summaries,
345 const CallEvent &Call,
346 QualType ReceiverType) {
347 const Expr *CE = Call.getOriginExpr();
348 AnyCall C =
349 CE ? *AnyCall::forExpr(CE)
350 : AnyCall::forDestructorCall(cast<CXXDestructorDecl>(Call.getDecl()));
351 return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
352 isReceiverUnconsumedSelf(Call), ReceiverType);
353}
354
George Karpenkov70c2ee32018-08-17 21:41:07 +0000355void RetainCountChecker::checkPostCall(const CallEvent &Call,
356 CheckerContext &C) const {
357 RetainSummaryManager &Summaries = getSummaryManager(C);
George Karpenkovefef49c2018-08-21 03:09:02 +0000358
359 // Leave null if no receiver.
360 QualType ReceiverType;
361 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
362 if (MC->isInstanceMessage()) {
363 SVal ReceiverV = MC->getReceiverSVal();
364 if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
365 if (const RefVal *T = getRefBinding(C.getState(), Sym))
366 ReceiverType = T->getType();
367 }
368 }
369
George Karpenkov6fdd2bd2019-01-25 01:24:04 +0000370 const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000371
372 if (C.wasInlined) {
373 processSummaryOfInlined(*Summ, Call, C);
374 return;
375 }
376 checkSummary(*Summ, Call, C);
377}
378
379/// GetReturnType - Used to get the return type of a message expression or
380/// function call with the intention of affixing that type to a tracked symbol.
381/// While the return type can be queried directly from RetEx, when
382/// invoking class methods we augment to the return type to be that of
383/// a pointer to the class (as opposed it just being id).
384// FIXME: We may be able to do this with related result types instead.
385// This function is probably overestimating.
386static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
387 QualType RetTy = RetE->getType();
388 // If RetE is not a message expression just return its type.
389 // If RetE is a message expression, return its types if it is something
390 /// more specific than id.
391 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
392 if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
393 if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
394 PT->isObjCClassType()) {
395 // At this point we know the return type of the message expression is
396 // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
397 // is a call to a class method whose type we can resolve. In such
398 // cases, promote the return type to XXX* (where XXX is the class).
399 const ObjCInterfaceDecl *D = ME->getReceiverInterface();
400 return !D ? RetTy :
401 Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D));
402 }
403
404 return RetTy;
405}
406
George Karpenkov80c9e782018-08-22 01:16:49 +0000407static Optional<RefVal> refValFromRetEffect(RetEffect RE,
408 QualType ResultTy) {
409 if (RE.isOwned()) {
410 return RefVal::makeOwned(RE.getObjKind(), ResultTy);
411 } else if (RE.notOwned()) {
412 return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
413 }
414
415 return None;
416}
417
George Karpenkov255b0582018-12-21 19:13:40 +0000418static bool isPointerToObject(QualType QT) {
419 QualType PT = QT->getPointeeType();
420 if (!PT.isNull())
421 if (PT->getAsCXXRecordDecl())
422 return true;
423 return false;
424}
425
426/// Whether the tracked value should be escaped on a given call.
427/// OSObjects are escaped when passed to void * / etc.
George Karpenkov9cbcc212019-01-10 18:14:12 +0000428static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx,
George Karpenkov255b0582018-12-21 19:13:40 +0000429 const RefVal *TrackedValue) {
George Karpenkov7e3016d2019-01-10 18:13:46 +0000430 if (TrackedValue->getObjKind() != ObjKind::OS)
George Karpenkov255b0582018-12-21 19:13:40 +0000431 return false;
432 if (ArgIdx >= CE.parameters().size())
433 return false;
434 return !isPointerToObject(CE.parameters()[ArgIdx]->getType());
435}
436
George Karpenkov70c2ee32018-08-17 21:41:07 +0000437// We don't always get the exact modeling of the function with regards to the
438// retain count checker even when the function is inlined. For example, we need
439// to stop tracking the symbols which were marked with StopTrackingHard.
440void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
441 const CallEvent &CallOrMsg,
442 CheckerContext &C) const {
443 ProgramStateRef state = C.getState();
444
445 // Evaluate the effect of the arguments.
446 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
George Karpenkov255b0582018-12-21 19:13:40 +0000447 SVal V = CallOrMsg.getArgSVal(idx);
448
449 if (SymbolRef Sym = V.getAsLocSymbol()) {
George Karpenkov585a2102019-01-10 18:13:59 +0000450 bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard;
George Karpenkov255b0582018-12-21 19:13:40 +0000451 if (const RefVal *T = getRefBinding(state, Sym))
George Karpenkov9cbcc212019-01-10 18:14:12 +0000452 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
George Karpenkov255b0582018-12-21 19:13:40 +0000453 ShouldRemoveBinding = true;
454
455 if (ShouldRemoveBinding)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000456 state = removeRefBinding(state, Sym);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000457 }
458 }
459
460 // Evaluate the effect on the message receiver.
George Karpenkov6e9fd132018-08-22 01:17:09 +0000461 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000462 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
George Karpenkov585a2102019-01-10 18:13:59 +0000463 if (Summ.getReceiverEffect().getKind() == StopTrackingHard) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000464 state = removeRefBinding(state, Sym);
465 }
466 }
467 }
468
469 // Consult the summary for the return value.
470 RetEffect RE = Summ.getRetEffect();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000471
George Karpenkovd5ef0d22018-08-29 20:28:33 +0000472 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
George Karpenkovd5ef0d22018-08-29 20:28:33 +0000473 if (RE.getKind() == RetEffect::NoRetHard)
474 state = removeRefBinding(state, Sym);
475 }
George Karpenkovab0011e2018-08-23 00:26:59 +0000476
George Karpenkov70c2ee32018-08-17 21:41:07 +0000477 C.addTransition(state);
478}
479
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000480static bool isSmartPtrField(const MemRegion *MR) {
481 const auto *TR = dyn_cast<TypedValueRegion>(
482 cast<SubRegion>(MR)->getSuperRegion());
483 return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType());
484}
485
486
George Karpenkov03391512019-01-16 23:21:38 +0000487/// A value escapes in these possible cases:
488///
489/// - binding to something that is not a memory region.
490/// - binding to a memregion that does not have stack storage
491/// - binding to a variable that has a destructor attached using CleanupAttr
492///
493/// We do not currently model what happens when a symbol is
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000494/// assigned to a struct field, unless it is a known smart pointer
495/// implementation, about which we know that it is inlined.
George Karpenkov03391512019-01-16 23:21:38 +0000496/// FIXME: This could definitely be improved upon.
George Karpenkov5be959c2019-01-11 23:35:17 +0000497static bool shouldEscapeRegion(const MemRegion *R) {
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000498 if (isSmartPtrField(R))
499 return false;
500
George Karpenkov03391512019-01-16 23:21:38 +0000501 const auto *VR = dyn_cast<VarRegion>(R);
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000502
George Karpenkov03391512019-01-16 23:21:38 +0000503 if (!R->hasStackStorage() || !VR)
504 return true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000505
George Karpenkov03391512019-01-16 23:21:38 +0000506 const VarDecl *VD = VR->getDecl();
507 if (!VD->hasAttr<CleanupAttr>())
508 return false; // CleanupAttr attaches destructors, which cause escaping.
509 return true;
George Karpenkov5be959c2019-01-11 23:35:17 +0000510}
George Karpenkov70c2ee32018-08-17 21:41:07 +0000511
George Karpenkov5be959c2019-01-11 23:35:17 +0000512static SmallVector<ProgramStateRef, 2>
513updateOutParameters(ProgramStateRef State, const RetainSummary &Summ,
514 const CallEvent &CE) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000515
George Karpenkov5be959c2019-01-11 23:35:17 +0000516 SVal L = CE.getReturnValue();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000517
George Karpenkov5be959c2019-01-11 23:35:17 +0000518 // Splitting is required to support out parameters,
519 // as out parameters might be created only on the "success" branch.
520 // We want to avoid eagerly splitting unless out parameters are actually
521 // needed.
522 bool SplitNecessary = false;
523 for (auto &P : Summ.getArgEffects())
524 if (P.second.getKind() == RetainedOutParameterOnNonZero ||
525 P.second.getKind() == RetainedOutParameterOnZero)
526 SplitNecessary = true;
527
528 ProgramStateRef AssumeNonZeroReturn = State;
529 ProgramStateRef AssumeZeroReturn = State;
530
531 if (SplitNecessary) {
532 if (auto DL = L.getAs<DefinedOrUnknownSVal>()) {
533 AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true);
534 AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false);
535 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000536 }
537
George Karpenkov5be959c2019-01-11 23:35:17 +0000538 for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) {
539 SVal ArgVal = CE.getArgSVal(idx);
540 ArgEffect AE = Summ.getArg(idx);
541
542 auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion());
543 if (!ArgRegion)
544 continue;
545
546 QualType PointeeTy = ArgRegion->getValueType();
547 SVal PointeeVal = State->getSVal(ArgRegion);
548 SymbolRef Pointee = PointeeVal.getAsLocSymbol();
549 if (!Pointee)
550 continue;
551
552 if (shouldEscapeRegion(ArgRegion))
553 continue;
554
555 auto makeNotOwnedParameter = [&](ProgramStateRef St) {
556 return setRefBinding(St, Pointee,
557 RefVal::makeNotOwned(AE.getObjKind(), PointeeTy));
558 };
559 auto makeOwnedParameter = [&](ProgramStateRef St) {
560 return setRefBinding(St, Pointee,
561 RefVal::makeOwned(ObjKind::OS, PointeeTy));
562 };
563
564 switch (AE.getKind()) {
565 case UnretainedOutParameter:
566 AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
567 AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
568 break;
569 case RetainedOutParameter:
570 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
571 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
572 break;
573 case RetainedOutParameterOnNonZero:
574 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
575 break;
576 case RetainedOutParameterOnZero:
577 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
578 break;
579 default:
580 break;
581 }
582 }
583
584 if (SplitNecessary) {
585 return {AssumeNonZeroReturn, AssumeZeroReturn};
586 } else {
587 assert(AssumeZeroReturn == AssumeNonZeroReturn);
588 return {AssumeZeroReturn};
589 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000590}
591
592void RetainCountChecker::checkSummary(const RetainSummary &Summ,
593 const CallEvent &CallOrMsg,
594 CheckerContext &C) const {
595 ProgramStateRef state = C.getState();
596
597 // Evaluate the effect of the arguments.
598 RefVal::Kind hasErr = (RefVal::Kind) 0;
599 SourceRange ErrorRange;
600 SymbolRef ErrorSym = nullptr;
601
George Karpenkov717c4c02019-01-10 18:15:17 +0000602 // Helper tag for providing diagnostics: indicate whether dealloc was sent
603 // at this location.
George Karpenkov717c4c02019-01-10 18:15:17 +0000604 bool DeallocSent = false;
605
George Karpenkov70c2ee32018-08-17 21:41:07 +0000606 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
607 SVal V = CallOrMsg.getArgSVal(idx);
608
George Karpenkov9cbcc212019-01-10 18:14:12 +0000609 ArgEffect Effect = Summ.getArg(idx);
George Karpenkov5be959c2019-01-11 23:35:17 +0000610 if (SymbolRef Sym = V.getAsLocSymbol()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000611 if (const RefVal *T = getRefBinding(state, Sym)) {
George Karpenkov041c9fa2018-12-08 01:18:40 +0000612
George Karpenkov9cbcc212019-01-10 18:14:12 +0000613 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
614 Effect = ArgEffect(StopTrackingHard, ObjKind::OS);
George Karpenkov041c9fa2018-12-08 01:18:40 +0000615
George Karpenkov70c2ee32018-08-17 21:41:07 +0000616 state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
617 if (hasErr) {
618 ErrorRange = CallOrMsg.getArgSourceRange(idx);
619 ErrorSym = Sym;
620 break;
George Karpenkov717c4c02019-01-10 18:15:17 +0000621 } else if (Effect.getKind() == Dealloc) {
622 DeallocSent = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000623 }
624 }
625 }
626 }
627
George Karpenkovab0011e2018-08-23 00:26:59 +0000628 // Evaluate the effect on the message receiver / `this` argument.
George Karpenkov70c2ee32018-08-17 21:41:07 +0000629 bool ReceiverIsTracked = false;
630 if (!hasErr) {
George Karpenkovab0011e2018-08-23 00:26:59 +0000631 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000632 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
633 if (const RefVal *T = getRefBinding(state, Sym)) {
634 ReceiverIsTracked = true;
George Karpenkov585a2102019-01-10 18:13:59 +0000635 state = updateSymbol(state, Sym, *T,
George Karpenkov9cbcc212019-01-10 18:14:12 +0000636 Summ.getReceiverEffect(), hasErr, C);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000637 if (hasErr) {
638 ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
639 ErrorSym = Sym;
George Karpenkov717c4c02019-01-10 18:15:17 +0000640 } else if (Summ.getReceiverEffect().getKind() == Dealloc) {
641 DeallocSent = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000642 }
643 }
644 }
George Karpenkovab0011e2018-08-23 00:26:59 +0000645 } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
646 if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
647 if (const RefVal *T = getRefBinding(state, Sym)) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000648 state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
George Karpenkovab0011e2018-08-23 00:26:59 +0000649 hasErr, C);
650 if (hasErr) {
651 ErrorRange = MCall->getOriginExpr()->getSourceRange();
652 ErrorSym = Sym;
653 }
654 }
655 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000656 }
657 }
658
659 // Process any errors.
660 if (hasErr) {
661 processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
662 return;
663 }
664
665 // Consult the summary for the return value.
666 RetEffect RE = Summ.getRetEffect();
667
668 if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
669 if (ReceiverIsTracked)
670 RE = getSummaryManager(C).getObjAllocRetEffect();
671 else
672 RE = RetEffect::MakeNoRet();
673 }
674
George Karpenkov80c9e782018-08-22 01:16:49 +0000675 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
676 QualType ResultTy = CallOrMsg.getResultType();
677 if (RE.notOwned()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000678 const Expr *Ex = CallOrMsg.getOriginExpr();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000679 assert(Ex);
George Karpenkov80c9e782018-08-22 01:16:49 +0000680 ResultTy = GetReturnType(Ex, C.getASTContext());
George Karpenkov70c2ee32018-08-17 21:41:07 +0000681 }
George Karpenkov80c9e782018-08-22 01:16:49 +0000682 if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
683 state = setRefBinding(state, Sym, *updatedRefVal);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000684 }
685
George Karpenkov5be959c2019-01-11 23:35:17 +0000686 SmallVector<ProgramStateRef, 2> Out =
687 updateOutParameters(state, Summ, CallOrMsg);
688
689 for (ProgramStateRef St : Out) {
690 if (DeallocSent) {
691 C.addTransition(St, C.getPredecessor(), &DeallocSentTag);
692 } else {
693 C.addTransition(St);
694 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000695 }
696}
697
George Karpenkov585a2102019-01-10 18:13:59 +0000698ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
699 SymbolRef sym, RefVal V,
George Karpenkov9cbcc212019-01-10 18:14:12 +0000700 ArgEffect AE,
George Karpenkov585a2102019-01-10 18:13:59 +0000701 RefVal::Kind &hasErr,
702 CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000703 bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000704 if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) {
705 switch (AE.getKind()) {
706 default:
707 break;
708 case IncRef:
709 AE = AE.withKind(DoNothing);
710 break;
711 case DecRef:
712 AE = AE.withKind(DoNothing);
713 break;
714 case DecRefAndStopTrackingHard:
715 AE = AE.withKind(StopTracking);
716 break;
717 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000718 }
719
720 // Handle all use-after-releases.
721 if (V.getKind() == RefVal::Released) {
722 V = V ^ RefVal::ErrorUseAfterRelease;
723 hasErr = V.getKind();
724 return setRefBinding(state, sym, V);
725 }
726
George Karpenkov9cbcc212019-01-10 18:14:12 +0000727 switch (AE.getKind()) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000728 case UnretainedOutParameter:
729 case RetainedOutParameter:
George Karpenkov5be959c2019-01-11 23:35:17 +0000730 case RetainedOutParameterOnZero:
731 case RetainedOutParameterOnNonZero:
George Karpenkov70c2ee32018-08-17 21:41:07 +0000732 llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
733 "not have ref state.");
734
George Karpenkov717c4c02019-01-10 18:15:17 +0000735 case Dealloc: // NB. we only need to add a note in a non-error case.
George Karpenkov70c2ee32018-08-17 21:41:07 +0000736 switch (V.getKind()) {
737 default:
738 llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
739 case RefVal::Owned:
740 // The object immediately transitions to the released state.
741 V = V ^ RefVal::Released;
742 V.clearCounts();
743 return setRefBinding(state, sym, V);
744 case RefVal::NotOwned:
745 V = V ^ RefVal::ErrorDeallocNotOwned;
746 hasErr = V.getKind();
747 break;
748 }
749 break;
750
751 case MayEscape:
752 if (V.getKind() == RefVal::Owned) {
753 V = V ^ RefVal::NotOwned;
754 break;
755 }
756
Reid Kleckner4dc0b1a2018-11-01 19:54:45 +0000757 LLVM_FALLTHROUGH;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000758
759 case DoNothing:
760 return state;
761
762 case Autorelease:
763 // Update the autorelease counts.
764 V = V.autorelease();
765 break;
766
767 case StopTracking:
768 case StopTrackingHard:
769 return removeRefBinding(state, sym);
770
771 case IncRef:
772 switch (V.getKind()) {
773 default:
774 llvm_unreachable("Invalid RefVal state for a retain.");
775 case RefVal::Owned:
776 case RefVal::NotOwned:
777 V = V + 1;
778 break;
779 }
780 break;
781
782 case DecRef:
783 case DecRefBridgedTransferred:
784 case DecRefAndStopTrackingHard:
785 switch (V.getKind()) {
786 default:
787 // case 'RefVal::Released' handled above.
788 llvm_unreachable("Invalid RefVal state for a release.");
789
790 case RefVal::Owned:
791 assert(V.getCount() > 0);
792 if (V.getCount() == 1) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000793 if (AE.getKind() == DecRefBridgedTransferred ||
George Karpenkov70c2ee32018-08-17 21:41:07 +0000794 V.getIvarAccessHistory() ==
795 RefVal::IvarAccessHistory::AccessedDirectly)
796 V = V ^ RefVal::NotOwned;
797 else
798 V = V ^ RefVal::Released;
George Karpenkov9cbcc212019-01-10 18:14:12 +0000799 } else if (AE.getKind() == DecRefAndStopTrackingHard) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000800 return removeRefBinding(state, sym);
801 }
802
803 V = V - 1;
804 break;
805
806 case RefVal::NotOwned:
807 if (V.getCount() > 0) {
George Karpenkov9cbcc212019-01-10 18:14:12 +0000808 if (AE.getKind() == DecRefAndStopTrackingHard)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000809 return removeRefBinding(state, sym);
810 V = V - 1;
811 } else if (V.getIvarAccessHistory() ==
812 RefVal::IvarAccessHistory::AccessedDirectly) {
813 // Assume that the instance variable was holding on the object at
814 // +1, and we just didn't know.
George Karpenkov9cbcc212019-01-10 18:14:12 +0000815 if (AE.getKind() == DecRefAndStopTrackingHard)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000816 return removeRefBinding(state, sym);
817 V = V.releaseViaIvar() ^ RefVal::Released;
818 } else {
819 V = V ^ RefVal::ErrorReleaseNotOwned;
820 hasErr = V.getKind();
821 }
822 break;
823 }
824 break;
825 }
826 return setRefBinding(state, sym, V);
827}
828
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000829const RefCountBug &
830RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
831 SymbolRef Sym) const {
832 switch (ErrorKind) {
833 case RefVal::ErrorUseAfterRelease:
834 return useAfterRelease;
835 case RefVal::ErrorReleaseNotOwned:
836 return releaseNotOwned;
837 case RefVal::ErrorDeallocNotOwned:
838 if (Sym->getType()->getPointeeCXXRecordDecl())
839 return freeNotOwned;
840 return deallocNotOwned;
841 default:
842 llvm_unreachable("Unhandled error.");
843 }
844}
845
George Karpenkov70c2ee32018-08-17 21:41:07 +0000846void RetainCountChecker::processNonLeakError(ProgramStateRef St,
847 SourceRange ErrorRange,
848 RefVal::Kind ErrorKind,
849 SymbolRef Sym,
850 CheckerContext &C) const {
851 // HACK: Ignore retain-count issues on values accessed through ivars,
852 // because of cases like this:
853 // [_contentView retain];
854 // [_contentView removeFromSuperview];
855 // [self addSubview:_contentView]; // invalidates 'self'
856 // [_contentView release];
857 if (const RefVal *RV = getRefBinding(St, Sym))
858 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
859 return;
860
861 ExplodedNode *N = C.generateErrorNode(St);
862 if (!N)
863 return;
864
George Karpenkov0bb17c42019-01-10 18:16:25 +0000865 auto report = llvm::make_unique<RefCountReport>(
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000866 errorKindToBugKind(ErrorKind, Sym),
867 C.getASTContext().getLangOpts(), N, Sym);
George Karpenkov70c2ee32018-08-17 21:41:07 +0000868 report->addRange(ErrorRange);
869 C.emitReport(std::move(report));
870}
871
872//===----------------------------------------------------------------------===//
873// Handle the return values of retain-count-related functions.
874//===----------------------------------------------------------------------===//
875
876bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000877 ProgramStateRef state = C.getState();
878 const FunctionDecl *FD = C.getCalleeDecl(CE);
879 if (!FD)
880 return false;
881
George Karpenkovc4d6b932018-08-17 21:42:05 +0000882 RetainSummaryManager &SmrMgr = getSummaryManager(C);
883 QualType ResultTy = CE->getCallReturnType(C.getASTContext());
George Karpenkov70c2ee32018-08-17 21:41:07 +0000884
George Karpenkov70c2ee32018-08-17 21:41:07 +0000885 // See if the function has 'rc_ownership_trusted_implementation'
886 // annotate attribute. If it does, we will not inline it.
887 bool hasTrustedImplementationAnnotation = false;
888
George Karpenkov41dc8de2018-10-11 22:59:16 +0000889 const LocationContext *LCtx = C.getLocationContext();
890
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000891 using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
892 Optional<BehaviorSummary> BSmr =
893 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
894
George Karpenkovc4d6b932018-08-17 21:42:05 +0000895 // See if it's one of the specific functions we know how to eval.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000896 if (!BSmr)
George Karpenkov70c2ee32018-08-17 21:41:07 +0000897 return false;
898
899 // Bind the return value.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000900 if (BSmr == BehaviorSummary::Identity ||
George Karpenkovdb0c66e2019-01-22 19:50:47 +0000901 BSmr == BehaviorSummary::IdentityOrZero ||
902 BSmr == BehaviorSummary::IdentityThis) {
903
904 const Expr *BindReturnTo =
905 (BSmr == BehaviorSummary::IdentityThis)
906 ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
907 : CE->getArg(0);
908 SVal RetVal = state->getSVal(BindReturnTo, LCtx);
George Karpenkov48de5822018-10-23 23:11:30 +0000909
George Karpenkov70c2ee32018-08-17 21:41:07 +0000910 // If the receiver is unknown or the function has
911 // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
912 // return value.
George Karpenkovdb0c66e2019-01-22 19:50:47 +0000913 // FIXME: this branch is very strange.
George Karpenkov48de5822018-10-23 23:11:30 +0000914 if (RetVal.isUnknown() ||
915 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
916 SValBuilder &SVB = C.getSValBuilder();
917 RetVal =
918 SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
919 }
George Karpenkovdb0c66e2019-01-22 19:50:47 +0000920
921 // Bind the value.
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000922 state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
923
924 if (BSmr == BehaviorSummary::IdentityOrZero) {
925 // Add a branch where the output is zero.
926 ProgramStateRef NullOutputState = C.getState();
927
928 // Assume that output is zero on the other branch.
929 NullOutputState = NullOutputState->BindExpr(
930 CE, LCtx, C.getSValBuilder().makeNull(), /*Invalidate=*/false);
George Karpenkova9e29562019-01-22 19:51:00 +0000931 C.addTransition(NullOutputState, &CastFailTag);
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000932
933 // And on the original branch assume that both input and
934 // output are non-zero.
935 if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
936 state = state->assume(*L, /*Assumption=*/true);
937
938 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000939 }
George Karpenkov70c2ee32018-08-17 21:41:07 +0000940
George Karpenkov70c2ee32018-08-17 21:41:07 +0000941 C.addTransition(state);
942 return true;
943}
944
George Karpenkov04553e52018-09-21 20:37:20 +0000945ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
946 CheckerContext &C) const {
947 ExplodedNode *Pred = C.getPredecessor();
George Karpenkov70c2ee32018-08-17 21:41:07 +0000948
949 // Only adjust the reference count if this is the top-level call frame,
950 // and not the result of inlining. In the future, we should do
951 // better checking even for inlined calls, and see if they match
952 // with their expected semantics (e.g., the method should return a retained
953 // object, etc.).
954 if (!C.inTopFrame())
George Karpenkov04553e52018-09-21 20:37:20 +0000955 return Pred;
956
957 if (!S)
958 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000959
960 const Expr *RetE = S->getRetValue();
961 if (!RetE)
George Karpenkov04553e52018-09-21 20:37:20 +0000962 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000963
964 ProgramStateRef state = C.getState();
965 SymbolRef Sym =
966 state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol();
967 if (!Sym)
George Karpenkov04553e52018-09-21 20:37:20 +0000968 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000969
970 // Get the reference count binding (if any).
971 const RefVal *T = getRefBinding(state, Sym);
972 if (!T)
George Karpenkov04553e52018-09-21 20:37:20 +0000973 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000974
975 // Change the reference count.
976 RefVal X = *T;
977
978 switch (X.getKind()) {
979 case RefVal::Owned: {
980 unsigned cnt = X.getCount();
981 assert(cnt > 0);
982 X.setCount(cnt - 1);
983 X = X ^ RefVal::ReturnedOwned;
984 break;
985 }
986
987 case RefVal::NotOwned: {
988 unsigned cnt = X.getCount();
989 if (cnt) {
990 X.setCount(cnt - 1);
991 X = X ^ RefVal::ReturnedOwned;
George Karpenkov04553e52018-09-21 20:37:20 +0000992 } else {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000993 X = X ^ RefVal::ReturnedNotOwned;
994 }
995 break;
996 }
997
998 default:
George Karpenkov04553e52018-09-21 20:37:20 +0000999 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001000 }
1001
1002 // Update the binding.
1003 state = setRefBinding(state, Sym, X);
George Karpenkov04553e52018-09-21 20:37:20 +00001004 Pred = C.addTransition(state);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001005
1006 // At this point we have updated the state properly.
1007 // Everything after this is merely checking to see if the return value has
1008 // been over- or under-retained.
1009
1010 // Did we cache out?
1011 if (!Pred)
George Karpenkov04553e52018-09-21 20:37:20 +00001012 return nullptr;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001013
1014 // Update the autorelease counts.
1015 static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease");
George Karpenkov04553e52018-09-21 20:37:20 +00001016 state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001017
George Karpenkov04553e52018-09-21 20:37:20 +00001018 // Have we generated a sink node?
George Karpenkov70c2ee32018-08-17 21:41:07 +00001019 if (!state)
George Karpenkov04553e52018-09-21 20:37:20 +00001020 return nullptr;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001021
1022 // Get the updated binding.
1023 T = getRefBinding(state, Sym);
1024 assert(T);
1025 X = *T;
1026
1027 // Consult the summary of the enclosing method.
1028 RetainSummaryManager &Summaries = getSummaryManager(C);
1029 const Decl *CD = &Pred->getCodeDecl();
1030 RetEffect RE = RetEffect::MakeNoRet();
1031
1032 // FIXME: What is the convention for blocks? Is there one?
1033 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
1034 const RetainSummary *Summ = Summaries.getMethodSummary(MD);
1035 RE = Summ->getRetEffect();
1036 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
1037 if (!isa<CXXMethodDecl>(FD)) {
1038 const RetainSummary *Summ = Summaries.getFunctionSummary(FD);
1039 RE = Summ->getRetEffect();
1040 }
1041 }
1042
George Karpenkov04553e52018-09-21 20:37:20 +00001043 return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001044}
1045
George Karpenkov04553e52018-09-21 20:37:20 +00001046ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
George Karpenkov70c2ee32018-08-17 21:41:07 +00001047 CheckerContext &C,
1048 ExplodedNode *Pred,
1049 RetEffect RE, RefVal X,
1050 SymbolRef Sym,
1051 ProgramStateRef state) const {
1052 // HACK: Ignore retain-count issues on values accessed through ivars,
1053 // because of cases like this:
1054 // [_contentView retain];
1055 // [_contentView removeFromSuperview];
1056 // [self addSubview:_contentView]; // invalidates 'self'
1057 // [_contentView release];
1058 if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
George Karpenkov04553e52018-09-21 20:37:20 +00001059 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001060
1061 // Any leaks or other errors?
1062 if (X.isReturnedOwned() && X.getCount() == 0) {
1063 if (RE.getKind() != RetEffect::NoRet) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001064 if (!RE.isOwned()) {
George Karpenkov04553e52018-09-21 20:37:20 +00001065
George Karpenkov70c2ee32018-08-17 21:41:07 +00001066 // The returning type is a CF, we expect the enclosing method should
1067 // return ownership.
George Karpenkov70c2ee32018-08-17 21:41:07 +00001068 X = X ^ RefVal::ErrorLeakReturned;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001069
George Karpenkov70c2ee32018-08-17 21:41:07 +00001070 // Generate an error node.
1071 state = setRefBinding(state, Sym, X);
1072
1073 static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak");
1074 ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
1075 if (N) {
1076 const LangOptions &LOpts = C.getASTContext().getLangOpts();
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001077 auto R =
1078 llvm::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C);
George Karpenkov04553e52018-09-21 20:37:20 +00001079 C.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001080 }
George Karpenkov04553e52018-09-21 20:37:20 +00001081 return N;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001082 }
1083 }
1084 } else if (X.isReturnedNotOwned()) {
1085 if (RE.isOwned()) {
1086 if (X.getIvarAccessHistory() ==
1087 RefVal::IvarAccessHistory::AccessedDirectly) {
1088 // Assume the method was trying to transfer a +1 reference from a
1089 // strong ivar to the caller.
1090 state = setRefBinding(state, Sym,
1091 X.releaseViaIvar() ^ RefVal::ReturnedOwned);
1092 } else {
1093 // Trying to return a not owned object to a caller expecting an
1094 // owned object.
1095 state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
1096
1097 static CheckerProgramPointTag
1098 ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned");
1099
1100 ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
1101 if (N) {
George Karpenkov0bb17c42019-01-10 18:16:25 +00001102 auto R = llvm::make_unique<RefCountReport>(
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001103 returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
George Karpenkov04553e52018-09-21 20:37:20 +00001104 C.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001105 }
George Karpenkov04553e52018-09-21 20:37:20 +00001106 return N;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001107 }
1108 }
1109 }
George Karpenkov04553e52018-09-21 20:37:20 +00001110 return Pred;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001111}
1112
1113//===----------------------------------------------------------------------===//
1114// Check various ways a symbol can be invalidated.
1115//===----------------------------------------------------------------------===//
1116
1117void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
1118 CheckerContext &C) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001119 ProgramStateRef state = C.getState();
George Karpenkov03391512019-01-16 23:21:38 +00001120 const MemRegion *MR = loc.getAsRegion();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001121
George Karpenkov03391512019-01-16 23:21:38 +00001122 // Find all symbols referenced by 'val' that we are tracking
George Karpenkov70c2ee32018-08-17 21:41:07 +00001123 // and stop tracking them.
George Karpenkov03391512019-01-16 23:21:38 +00001124 if (MR && shouldEscapeRegion(MR)) {
1125 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
1126 C.addTransition(state);
1127 }
George Karpenkov70c2ee32018-08-17 21:41:07 +00001128}
1129
1130ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
George Karpenkov6e9fd132018-08-22 01:17:09 +00001131 SVal Cond,
1132 bool Assumption) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001133 // FIXME: We may add to the interface of evalAssume the list of symbols
1134 // whose assumptions have changed. For now we just iterate through the
1135 // bindings and check if any of the tracked symbols are NULL. This isn't
1136 // too bad since the number of symbols we will track in practice are
1137 // probably small and evalAssume is only called at branches and a few
1138 // other places.
1139 RefBindingsTy B = state->get<RefBindings>();
1140
1141 if (B.isEmpty())
1142 return state;
1143
1144 bool changed = false;
1145 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
George Karpenkov03391512019-01-16 23:21:38 +00001146 ConstraintManager &CMgr = state->getConstraintManager();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001147
George Karpenkov03391512019-01-16 23:21:38 +00001148 for (auto &I : B) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001149 // Check if the symbol is null stop tracking the symbol.
George Karpenkov03391512019-01-16 23:21:38 +00001150 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001151 if (AllocFailed.isConstrainedTrue()) {
1152 changed = true;
George Karpenkov03391512019-01-16 23:21:38 +00001153 B = RefBFactory.remove(B, I.first);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001154 }
1155 }
1156
1157 if (changed)
1158 state = state->set<RefBindings>(B);
1159
1160 return state;
1161}
1162
George Karpenkovf153cdf2019-01-16 23:21:15 +00001163ProgramStateRef RetainCountChecker::checkRegionChanges(
1164 ProgramStateRef state, const InvalidatedSymbols *invalidated,
1165 ArrayRef<const MemRegion *> ExplicitRegions,
1166 ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
1167 const CallEvent *Call) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001168 if (!invalidated)
1169 return state;
1170
1171 llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001172
George Karpenkovf153cdf2019-01-16 23:21:15 +00001173 for (const MemRegion *I : ExplicitRegions)
1174 if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
1175 WhitelistedSymbols.insert(SR->getSymbol());
1176
1177 for (SymbolRef sym : *invalidated) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001178 if (WhitelistedSymbols.count(sym))
1179 continue;
1180 // Remove any existing reference-count binding.
1181 state = removeRefBinding(state, sym);
1182 }
1183 return state;
1184}
1185
George Karpenkov70c2ee32018-08-17 21:41:07 +00001186ProgramStateRef
1187RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
1188 ExplodedNode *Pred,
1189 const ProgramPointTag *Tag,
1190 CheckerContext &Ctx,
George Karpenkov04553e52018-09-21 20:37:20 +00001191 SymbolRef Sym,
1192 RefVal V,
1193 const ReturnStmt *S) const {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001194 unsigned ACnt = V.getAutoreleaseCount();
1195
1196 // No autorelease counts? Nothing to be done.
1197 if (!ACnt)
1198 return state;
1199
1200 unsigned Cnt = V.getCount();
1201
1202 // FIXME: Handle sending 'autorelease' to already released object.
1203
1204 if (V.getKind() == RefVal::ReturnedOwned)
1205 ++Cnt;
1206
1207 // If we would over-release here, but we know the value came from an ivar,
1208 // assume it was a strong ivar that's just been relinquished.
1209 if (ACnt > Cnt &&
1210 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
1211 V = V.releaseViaIvar();
1212 --ACnt;
1213 }
1214
1215 if (ACnt <= Cnt) {
1216 if (ACnt == Cnt) {
1217 V.clearCounts();
George Karpenkov04553e52018-09-21 20:37:20 +00001218 if (V.getKind() == RefVal::ReturnedOwned) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001219 V = V ^ RefVal::ReturnedNotOwned;
George Karpenkov04553e52018-09-21 20:37:20 +00001220 } else {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001221 V = V ^ RefVal::NotOwned;
George Karpenkov04553e52018-09-21 20:37:20 +00001222 }
George Karpenkov70c2ee32018-08-17 21:41:07 +00001223 } else {
1224 V.setCount(V.getCount() - ACnt);
1225 V.setAutoreleaseCount(0);
1226 }
1227 return setRefBinding(state, Sym, V);
1228 }
1229
1230 // HACK: Ignore retain-count issues on values accessed through ivars,
1231 // because of cases like this:
1232 // [_contentView retain];
1233 // [_contentView removeFromSuperview];
1234 // [self addSubview:_contentView]; // invalidates 'self'
1235 // [_contentView release];
1236 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1237 return state;
1238
1239 // Woah! More autorelease counts then retain counts left.
1240 // Emit hard error.
1241 V = V ^ RefVal::ErrorOverAutorelease;
1242 state = setRefBinding(state, Sym, V);
1243
1244 ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
1245 if (N) {
1246 SmallString<128> sbuf;
1247 llvm::raw_svector_ostream os(sbuf);
1248 os << "Object was autoreleased ";
1249 if (V.getAutoreleaseCount() > 1)
1250 os << V.getAutoreleaseCount() << " times but the object ";
1251 else
1252 os << "but ";
1253 os << "has a +" << V.getCount() << " retain count";
1254
George Karpenkov70c2ee32018-08-17 21:41:07 +00001255 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001256 auto R = llvm::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym,
1257 os.str());
George Karpenkov04553e52018-09-21 20:37:20 +00001258 Ctx.emitReport(std::move(R));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001259 }
1260
1261 return nullptr;
1262}
1263
1264ProgramStateRef
1265RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
1266 SymbolRef sid, RefVal V,
1267 SmallVectorImpl<SymbolRef> &Leaked) const {
1268 bool hasLeak;
1269
1270 // HACK: Ignore retain-count issues on values accessed through ivars,
1271 // because of cases like this:
1272 // [_contentView retain];
1273 // [_contentView removeFromSuperview];
1274 // [self addSubview:_contentView]; // invalidates 'self'
1275 // [_contentView release];
1276 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1277 hasLeak = false;
1278 else if (V.isOwned())
1279 hasLeak = true;
1280 else if (V.isNotOwned() || V.isReturnedOwned())
1281 hasLeak = (V.getCount() > 0);
1282 else
1283 hasLeak = false;
1284
1285 if (!hasLeak)
1286 return removeRefBinding(state, sid);
1287
1288 Leaked.push_back(sid);
1289 return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
1290}
1291
1292ExplodedNode *
1293RetainCountChecker::processLeaks(ProgramStateRef state,
1294 SmallVectorImpl<SymbolRef> &Leaked,
1295 CheckerContext &Ctx,
1296 ExplodedNode *Pred) const {
1297 // Generate an intermediate node representing the leak point.
1298 ExplodedNode *N = Ctx.addTransition(state, Pred);
George Karpenkovf153cdf2019-01-16 23:21:15 +00001299 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001300
1301 if (N) {
George Karpenkovf153cdf2019-01-16 23:21:15 +00001302 for (SymbolRef L : Leaked) {
George Karpenkov2c2d0b62019-01-18 19:24:55 +00001303 const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn;
1304 Ctx.emitReport(llvm::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001305 }
1306 }
1307
1308 return N;
1309}
1310
George Karpenkovb1b791b2018-08-17 21:43:27 +00001311static bool isISLObjectRef(QualType Ty) {
1312 return StringRef(Ty.getAsString()).startswith("isl_");
George Karpenkov70c2ee32018-08-17 21:41:07 +00001313}
1314
1315void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
1316 if (!Ctx.inTopFrame())
1317 return;
1318
George Karpenkovc4d6b932018-08-17 21:42:05 +00001319 RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001320 const LocationContext *LCtx = Ctx.getLocationContext();
1321 const FunctionDecl *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
1322
George Karpenkovc4d6b932018-08-17 21:42:05 +00001323 if (!FD || SmrMgr.isTrustedReferenceCountImplementation(FD))
George Karpenkov70c2ee32018-08-17 21:41:07 +00001324 return;
1325
1326 ProgramStateRef state = Ctx.getState();
George Karpenkovc4d6b932018-08-17 21:42:05 +00001327 const RetainSummary *FunctionSummary = SmrMgr.getFunctionSummary(FD);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001328 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
1329
1330 for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) {
1331 const ParmVarDecl *Param = FD->getParamDecl(idx);
1332 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
1333
1334 QualType Ty = Param->getType();
1335 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
George Karpenkov585a2102019-01-10 18:13:59 +00001336 if (AE && AE->getKind() == DecRef && isISLObjectRef(Ty)) {
George Karpenkov6e9fd132018-08-22 01:17:09 +00001337 state = setRefBinding(
George Karpenkov7e3016d2019-01-10 18:13:46 +00001338 state, Sym, RefVal::makeOwned(ObjKind::Generalized, Ty));
George Karpenkovb1b791b2018-08-17 21:43:27 +00001339 } else if (isISLObjectRef(Ty)) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001340 state = setRefBinding(
1341 state, Sym,
George Karpenkov7e3016d2019-01-10 18:13:46 +00001342 RefVal::makeNotOwned(ObjKind::Generalized, Ty));
George Karpenkov70c2ee32018-08-17 21:41:07 +00001343 }
1344 }
1345
1346 Ctx.addTransition(state);
1347}
1348
1349void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
1350 CheckerContext &Ctx) const {
George Karpenkov04553e52018-09-21 20:37:20 +00001351 ExplodedNode *Pred = processReturn(RS, Ctx);
1352
1353 // Created state cached out.
1354 if (!Pred) {
1355 return;
1356 }
1357
1358 ProgramStateRef state = Pred->getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001359 RefBindingsTy B = state->get<RefBindings>();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001360
1361 // Don't process anything within synthesized bodies.
1362 const LocationContext *LCtx = Pred->getLocationContext();
1363 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
1364 assert(!LCtx->inTopFrame());
1365 return;
1366 }
1367
George Karpenkov03391512019-01-16 23:21:38 +00001368 for (auto &I : B) {
George Karpenkov70c2ee32018-08-17 21:41:07 +00001369 state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx,
George Karpenkov03391512019-01-16 23:21:38 +00001370 I.first, I.second);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001371 if (!state)
1372 return;
1373 }
1374
1375 // If the current LocationContext has a parent, don't check for leaks.
1376 // We will do that later.
1377 // FIXME: we should instead check for imbalances of the retain/releases,
1378 // and suggest annotations.
1379 if (LCtx->getParent())
1380 return;
1381
1382 B = state->get<RefBindings>();
1383 SmallVector<SymbolRef, 10> Leaked;
1384
George Karpenkov03391512019-01-16 23:21:38 +00001385 for (auto &I : B)
1386 state = handleSymbolDeath(state, I.first, I.second, Leaked);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001387
1388 processLeaks(state, Leaked, Ctx, Pred);
1389}
1390
George Karpenkov70c2ee32018-08-17 21:41:07 +00001391void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1392 CheckerContext &C) const {
1393 ExplodedNode *Pred = C.getPredecessor();
1394
1395 ProgramStateRef state = C.getState();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001396 SmallVector<SymbolRef, 10> Leaked;
1397
1398 // Update counts from autorelease pools
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001399 for (const auto &I: state->get<RefBindings>()) {
1400 SymbolRef Sym = I.first;
1401 if (SymReaper.isDead(Sym)) {
Artem Dergachev65b4d7d2018-10-15 17:47:56 +00001402 static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease");
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001403 const RefVal &V = I.second;
1404 state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001405 if (!state)
1406 return;
1407
1408 // Fetch the new reference count from the state, and use it to handle
1409 // this symbol.
Artem Dergachevbbc6d682018-11-30 03:27:50 +00001410 state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001411 }
1412 }
1413
1414 if (Leaked.empty()) {
1415 C.addTransition(state);
1416 return;
1417 }
1418
1419 Pred = processLeaks(state, Leaked, C, Pred);
1420
1421 // Did we cache out?
1422 if (!Pred)
1423 return;
1424
1425 // Now generate a new node that nukes the old bindings.
1426 // The only bindings left at this point are the leaked symbols.
1427 RefBindingsTy::Factory &F = state->get_context<RefBindings>();
George Karpenkovf153cdf2019-01-16 23:21:15 +00001428 RefBindingsTy B = state->get<RefBindings>();
George Karpenkov70c2ee32018-08-17 21:41:07 +00001429
George Karpenkovf153cdf2019-01-16 23:21:15 +00001430 for (SymbolRef L : Leaked)
1431 B = F.remove(B, L);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001432
1433 state = state->set<RefBindings>(B);
1434 C.addTransition(state, Pred);
1435}
1436
1437void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
1438 const char *NL, const char *Sep) const {
1439
1440 RefBindingsTy B = State->get<RefBindings>();
1441
1442 if (B.isEmpty())
1443 return;
1444
1445 Out << Sep << NL;
1446
George Karpenkov03391512019-01-16 23:21:38 +00001447 for (auto &I : B) {
1448 Out << I.first << " : ";
1449 I.second.print(Out);
George Karpenkov70c2ee32018-08-17 21:41:07 +00001450 Out << NL;
1451 }
1452}
1453
1454//===----------------------------------------------------------------------===//
George Karpenkov70c2ee32018-08-17 21:41:07 +00001455// Checker registration.
1456//===----------------------------------------------------------------------===//
1457
Kristof Umann8fd74eb2019-01-26 20:06:54 +00001458void ento::registerRetainCountBase(CheckerManager &Mgr) {
1459 Mgr.registerChecker<RetainCountChecker>();
1460}
1461
1462bool ento::shouldRegisterRetainCountBase(const LangOptions &LO) {
1463 return true;
1464}
1465
George Karpenkov70c2ee32018-08-17 21:41:07 +00001466void ento::registerRetainCountChecker(CheckerManager &Mgr) {
Kristof Umann204bf2b2019-01-26 21:41:50 +00001467 auto *Chk = Mgr.getChecker<RetainCountChecker>();
George Karpenkov27db3302018-12-07 20:21:51 +00001468 Chk->TrackObjCAndCFObjects = true;
1469}
Kristof Umannc83b0dd2018-11-02 15:48:10 +00001470
Kristof Umann058a7a42019-01-26 14:23:08 +00001471bool ento::shouldRegisterRetainCountChecker(const LangOptions &LO) {
1472 return true;
1473}
1474
George Karpenkovd1081ec2018-12-11 01:13:58 +00001475// FIXME: remove this, hack for backwards compatibility:
1476// it should be possible to enable the NS/CF retain count checker as
1477// osx.cocoa.RetainCount, and it should be possible to disable
1478// osx.OSObjectRetainCount using osx.cocoa.RetainCount:CheckOSObject=false.
1479static bool hasPrevCheckOSObjectOptionDisabled(AnalyzerOptions &Options) {
1480 auto I = Options.Config.find("osx.cocoa.RetainCount:CheckOSObject");
1481 if (I != Options.Config.end())
1482 return I->getValue() == "false";
1483 return false;
1484}
1485
George Karpenkov27db3302018-12-07 20:21:51 +00001486void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
Kristof Umann204bf2b2019-01-26 21:41:50 +00001487 auto *Chk = Mgr.getChecker<RetainCountChecker>();
George Karpenkovd1081ec2018-12-11 01:13:58 +00001488 if (!hasPrevCheckOSObjectOptionDisabled(Mgr.getAnalyzerOptions()))
1489 Chk->TrackOSObjects = true;
George Karpenkov70c2ee32018-08-17 21:41:07 +00001490}
Kristof Umann058a7a42019-01-26 14:23:08 +00001491
1492bool ento::shouldRegisterOSObjectRetainCountChecker(const LangOptions &LO) {
1493 return true;
1494}