1 //==-- RetainCountChecker.cpp - Checks for leaks and other issues -*- C++ -*--//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines 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 #include "clang/StaticAnalyzer/Core/Checker.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17 #include <optional>
18
19 using namespace clang;
20 using namespace ento;
21 using namespace retaincountchecker;
22
23 REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
24
25 namespace clang {
26 namespace ento {
27 namespace retaincountchecker {
28
getRefBinding(ProgramStateRef State,SymbolRef Sym)29 const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) {
30 return State->get<RefBindings>(Sym);
31 }
32
33 } // end namespace retaincountchecker
34 } // end namespace ento
35 } // end namespace clang
36
setRefBinding(ProgramStateRef State,SymbolRef Sym,RefVal Val)37 static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym,
38 RefVal Val) {
39 assert(Sym != nullptr);
40 return State->set<RefBindings>(Sym, Val);
41 }
42
removeRefBinding(ProgramStateRef State,SymbolRef Sym)43 static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) {
44 return State->remove<RefBindings>(Sym);
45 }
46
print(raw_ostream & Out) const47 void RefVal::print(raw_ostream &Out) const {
48 if (!T.isNull())
49 Out << "Tracked " << T << " | ";
50
51 switch (getKind()) {
52 default: llvm_unreachable("Invalid RefVal kind");
53 case Owned: {
54 Out << "Owned";
55 unsigned cnt = getCount();
56 if (cnt) Out << " (+ " << cnt << ")";
57 break;
58 }
59
60 case NotOwned: {
61 Out << "NotOwned";
62 unsigned cnt = getCount();
63 if (cnt) Out << " (+ " << cnt << ")";
64 break;
65 }
66
67 case ReturnedOwned: {
68 Out << "ReturnedOwned";
69 unsigned cnt = getCount();
70 if (cnt) Out << " (+ " << cnt << ")";
71 break;
72 }
73
74 case ReturnedNotOwned: {
75 Out << "ReturnedNotOwned";
76 unsigned cnt = getCount();
77 if (cnt) Out << " (+ " << cnt << ")";
78 break;
79 }
80
81 case Released:
82 Out << "Released";
83 break;
84
85 case ErrorDeallocNotOwned:
86 Out << "-dealloc (not-owned)";
87 break;
88
89 case ErrorLeak:
90 Out << "Leaked";
91 break;
92
93 case ErrorLeakReturned:
94 Out << "Leaked (Bad naming)";
95 break;
96
97 case ErrorUseAfterRelease:
98 Out << "Use-After-Release [ERROR]";
99 break;
100
101 case ErrorReleaseNotOwned:
102 Out << "Release of Not-Owned [ERROR]";
103 break;
104
105 case RefVal::ErrorOverAutorelease:
106 Out << "Over-autoreleased";
107 break;
108
109 case RefVal::ErrorReturnedNotOwned:
110 Out << "Non-owned object returned instead of owned";
111 break;
112 }
113
114 switch (getIvarAccessHistory()) {
115 case IvarAccessHistory::None:
116 break;
117 case IvarAccessHistory::AccessedDirectly:
118 Out << " [direct ivar access]";
119 break;
120 case IvarAccessHistory::ReleasedAfterDirectAccess:
121 Out << " [released after direct ivar access]";
122 }
123
124 if (ACnt) {
125 Out << " [autorelease -" << ACnt << ']';
126 }
127 }
128
129 namespace {
130 class StopTrackingCallback final : public SymbolVisitor {
131 ProgramStateRef state;
132 public:
StopTrackingCallback(ProgramStateRef st)133 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
getState() const134 ProgramStateRef getState() const { return state; }
135
VisitSymbol(SymbolRef sym)136 bool VisitSymbol(SymbolRef sym) override {
137 state = removeRefBinding(state, sym);
138 return true;
139 }
140 };
141 } // end anonymous namespace
142
143 //===----------------------------------------------------------------------===//
144 // Handle statements that may have an effect on refcounts.
145 //===----------------------------------------------------------------------===//
146
checkPostStmt(const BlockExpr * BE,CheckerContext & C) const147 void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
148 CheckerContext &C) const {
149
150 // Scan the BlockDecRefExprs for any object the retain count checker
151 // may be tracking.
152 if (!BE->getBlockDecl()->hasCaptures())
153 return;
154
155 ProgramStateRef state = C.getState();
156 auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
157
158 BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
159 E = R->referenced_vars_end();
160
161 if (I == E)
162 return;
163
164 // FIXME: For now we invalidate the tracking of all symbols passed to blocks
165 // via captured variables, even though captured variables result in a copy
166 // and in implicit increment/decrement of a retain count.
167 SmallVector<const MemRegion*, 10> Regions;
168 const LocationContext *LC = C.getLocationContext();
169 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
170
171 for ( ; I != E; ++I) {
172 const VarRegion *VR = I.getCapturedRegion();
173 if (VR->getSuperRegion() == R) {
174 VR = MemMgr.getVarRegion(VR->getDecl(), LC);
175 }
176 Regions.push_back(VR);
177 }
178
179 state = state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
180 C.addTransition(state);
181 }
182
checkPostStmt(const CastExpr * CE,CheckerContext & C) const183 void RetainCountChecker::checkPostStmt(const CastExpr *CE,
184 CheckerContext &C) const {
185 const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
186 if (!BE)
187 return;
188
189 QualType QT = CE->getType();
190 ObjKind K;
191 if (QT->isObjCObjectPointerType()) {
192 K = ObjKind::ObjC;
193 } else {
194 K = ObjKind::CF;
195 }
196
197 ArgEffect AE = ArgEffect(IncRef, K);
198
199 switch (BE->getBridgeKind()) {
200 case OBC_Bridge:
201 // Do nothing.
202 return;
203 case OBC_BridgeRetained:
204 AE = AE.withKind(IncRef);
205 break;
206 case OBC_BridgeTransfer:
207 AE = AE.withKind(DecRefBridgedTransferred);
208 break;
209 }
210
211 ProgramStateRef state = C.getState();
212 SymbolRef Sym = C.getSVal(CE).getAsLocSymbol();
213 if (!Sym)
214 return;
215 const RefVal* T = getRefBinding(state, Sym);
216 if (!T)
217 return;
218
219 RefVal::Kind hasErr = (RefVal::Kind) 0;
220 state = updateSymbol(state, Sym, *T, AE, hasErr, C);
221
222 if (hasErr) {
223 // FIXME: If we get an error during a bridge cast, should we report it?
224 return;
225 }
226
227 C.addTransition(state);
228 }
229
processObjCLiterals(CheckerContext & C,const Expr * Ex) const230 void RetainCountChecker::processObjCLiterals(CheckerContext &C,
231 const Expr *Ex) const {
232 ProgramStateRef state = C.getState();
233 const ExplodedNode *pred = C.getPredecessor();
234 for (const Stmt *Child : Ex->children()) {
235 SVal V = pred->getSVal(Child);
236 if (SymbolRef sym = V.getAsSymbol())
237 if (const RefVal* T = getRefBinding(state, sym)) {
238 RefVal::Kind hasErr = (RefVal::Kind) 0;
239 state = updateSymbol(state, sym, *T,
240 ArgEffect(MayEscape, ObjKind::ObjC), hasErr, C);
241 if (hasErr) {
242 processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C);
243 return;
244 }
245 }
246 }
247
248 // Return the object as autoreleased.
249 // RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC);
250 if (SymbolRef sym =
251 state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
252 QualType ResultTy = Ex->getType();
253 state = setRefBinding(state, sym,
254 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
255 }
256
257 C.addTransition(state);
258 }
259
checkPostStmt(const ObjCArrayLiteral * AL,CheckerContext & C) const260 void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
261 CheckerContext &C) const {
262 // Apply the 'MayEscape' to all values.
263 processObjCLiterals(C, AL);
264 }
265
checkPostStmt(const ObjCDictionaryLiteral * DL,CheckerContext & C) const266 void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
267 CheckerContext &C) const {
268 // Apply the 'MayEscape' to all keys and values.
269 processObjCLiterals(C, DL);
270 }
271
checkPostStmt(const ObjCBoxedExpr * Ex,CheckerContext & C) const272 void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
273 CheckerContext &C) const {
274 const ExplodedNode *Pred = C.getPredecessor();
275 ProgramStateRef State = Pred->getState();
276
277 if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) {
278 QualType ResultTy = Ex->getType();
279 State = setRefBinding(State, Sym,
280 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
281 }
282
283 C.addTransition(State);
284 }
285
checkPostStmt(const ObjCIvarRefExpr * IRE,CheckerContext & C) const286 void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
287 CheckerContext &C) const {
288 std::optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
289 if (!IVarLoc)
290 return;
291
292 ProgramStateRef State = C.getState();
293 SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
294 if (!Sym || !isa_and_nonnull<ObjCIvarRegion>(Sym->getOriginRegion()))
295 return;
296
297 // Accessing an ivar directly is unusual. If we've done that, be more
298 // forgiving about what the surrounding code is allowed to do.
299
300 QualType Ty = Sym->getType();
301 ObjKind Kind;
302 if (Ty->isObjCRetainableType())
303 Kind = ObjKind::ObjC;
304 else if (coreFoundation::isCFObjectRef(Ty))
305 Kind = ObjKind::CF;
306 else
307 return;
308
309 // If the value is already known to be nil, don't bother tracking it.
310 ConstraintManager &CMgr = State->getConstraintManager();
311 if (CMgr.isNull(State, Sym).isConstrainedTrue())
312 return;
313
314 if (const RefVal *RV = getRefBinding(State, Sym)) {
315 // If we've seen this symbol before, or we're only seeing it now because
316 // of something the analyzer has synthesized, don't do anything.
317 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None ||
318 isSynthesizedAccessor(C.getStackFrame())) {
319 return;
320 }
321
322 // Note that this value has been loaded from an ivar.
323 C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
324 return;
325 }
326
327 RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty);
328
329 // In a synthesized accessor, the effective retain count is +0.
330 if (isSynthesizedAccessor(C.getStackFrame())) {
331 C.addTransition(setRefBinding(State, Sym, PlusZero));
332 return;
333 }
334
335 State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
336 C.addTransition(State);
337 }
338
isReceiverUnconsumedSelf(const CallEvent & Call)339 static bool isReceiverUnconsumedSelf(const CallEvent &Call) {
340 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
341
342 // Check if the message is not consumed, we know it will not be used in
343 // an assignment, ex: "self = [super init]".
344 return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
345 !Call.getLocationContext()
346 ->getAnalysisDeclContext()
347 ->getParentMap()
348 .isConsumedExpr(Call.getOriginExpr());
349 }
350 return false;
351 }
352
getSummary(RetainSummaryManager & Summaries,const CallEvent & Call,QualType ReceiverType)353 const static RetainSummary *getSummary(RetainSummaryManager &Summaries,
354 const CallEvent &Call,
355 QualType ReceiverType) {
356 const Expr *CE = Call.getOriginExpr();
357 AnyCall C =
358 CE ? *AnyCall::forExpr(CE)
359 : AnyCall(cast<CXXDestructorDecl>(Call.getDecl()));
360 return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
361 isReceiverUnconsumedSelf(Call), ReceiverType);
362 }
363
checkPostCall(const CallEvent & Call,CheckerContext & C) const364 void RetainCountChecker::checkPostCall(const CallEvent &Call,
365 CheckerContext &C) const {
366 RetainSummaryManager &Summaries = getSummaryManager(C);
367
368 // Leave null if no receiver.
369 QualType ReceiverType;
370 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
371 if (MC->isInstanceMessage()) {
372 SVal ReceiverV = MC->getReceiverSVal();
373 if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
374 if (const RefVal *T = getRefBinding(C.getState(), Sym))
375 ReceiverType = T->getType();
376 }
377 }
378
379 const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType);
380
381 if (C.wasInlined) {
382 processSummaryOfInlined(*Summ, Call, C);
383 return;
384 }
385 checkSummary(*Summ, Call, C);
386 }
387
388 /// GetReturnType - Used to get the return type of a message expression or
389 /// function call with the intention of affixing that type to a tracked symbol.
390 /// While the return type can be queried directly from RetEx, when
391 /// invoking class methods we augment to the return type to be that of
392 /// a pointer to the class (as opposed it just being id).
393 // FIXME: We may be able to do this with related result types instead.
394 // This function is probably overestimating.
GetReturnType(const Expr * RetE,ASTContext & Ctx)395 static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
396 QualType RetTy = RetE->getType();
397 // If RetE is not a message expression just return its type.
398 // If RetE is a message expression, return its types if it is something
399 /// more specific than id.
400 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
401 if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
402 if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
403 PT->isObjCClassType()) {
404 // At this point we know the return type of the message expression is
405 // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
406 // is a call to a class method whose type we can resolve. In such
407 // cases, promote the return type to XXX* (where XXX is the class).
408 const ObjCInterfaceDecl *D = ME->getReceiverInterface();
409 return !D ? RetTy :
410 Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D));
411 }
412
413 return RetTy;
414 }
415
refValFromRetEffect(RetEffect RE,QualType ResultTy)416 static std::optional<RefVal> refValFromRetEffect(RetEffect RE,
417 QualType ResultTy) {
418 if (RE.isOwned()) {
419 return RefVal::makeOwned(RE.getObjKind(), ResultTy);
420 } else if (RE.notOwned()) {
421 return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
422 }
423
424 return std::nullopt;
425 }
426
isPointerToObject(QualType QT)427 static bool isPointerToObject(QualType QT) {
428 QualType PT = QT->getPointeeType();
429 if (!PT.isNull())
430 if (PT->getAsCXXRecordDecl())
431 return true;
432 return false;
433 }
434
435 /// Whether the tracked value should be escaped on a given call.
436 /// OSObjects are escaped when passed to void * / etc.
shouldEscapeOSArgumentOnCall(const CallEvent & CE,unsigned ArgIdx,const RefVal * TrackedValue)437 static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx,
438 const RefVal *TrackedValue) {
439 if (TrackedValue->getObjKind() != ObjKind::OS)
440 return false;
441 if (ArgIdx >= CE.parameters().size())
442 return false;
443 return !isPointerToObject(CE.parameters()[ArgIdx]->getType());
444 }
445
446 // We don't always get the exact modeling of the function with regards to the
447 // retain count checker even when the function is inlined. For example, we need
448 // to stop tracking the symbols which were marked with StopTrackingHard.
processSummaryOfInlined(const RetainSummary & Summ,const CallEvent & CallOrMsg,CheckerContext & C) const449 void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
450 const CallEvent &CallOrMsg,
451 CheckerContext &C) const {
452 ProgramStateRef state = C.getState();
453
454 // Evaluate the effect of the arguments.
455 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
456 SVal V = CallOrMsg.getArgSVal(idx);
457
458 if (SymbolRef Sym = V.getAsLocSymbol()) {
459 bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard;
460 if (const RefVal *T = getRefBinding(state, Sym))
461 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
462 ShouldRemoveBinding = true;
463
464 if (ShouldRemoveBinding)
465 state = removeRefBinding(state, Sym);
466 }
467 }
468
469 // Evaluate the effect on the message receiver.
470 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
471 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
472 if (Summ.getReceiverEffect().getKind() == StopTrackingHard) {
473 state = removeRefBinding(state, Sym);
474 }
475 }
476 }
477
478 // Consult the summary for the return value.
479 RetEffect RE = Summ.getRetEffect();
480
481 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
482 if (RE.getKind() == RetEffect::NoRetHard)
483 state = removeRefBinding(state, Sym);
484 }
485
486 C.addTransition(state);
487 }
488
isSmartPtrField(const MemRegion * MR)489 static bool isSmartPtrField(const MemRegion *MR) {
490 const auto *TR = dyn_cast<TypedValueRegion>(
491 cast<SubRegion>(MR)->getSuperRegion());
492 return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType());
493 }
494
495
496 /// A value escapes in these possible cases:
497 ///
498 /// - binding to something that is not a memory region.
499 /// - binding to a memregion that does not have stack storage
500 /// - binding to a variable that has a destructor attached using CleanupAttr
501 ///
502 /// We do not currently model what happens when a symbol is
503 /// assigned to a struct field, unless it is a known smart pointer
504 /// implementation, about which we know that it is inlined.
505 /// FIXME: This could definitely be improved upon.
shouldEscapeRegion(const MemRegion * R)506 static bool shouldEscapeRegion(const MemRegion *R) {
507 if (isSmartPtrField(R))
508 return false;
509
510 const auto *VR = dyn_cast<VarRegion>(R);
511
512 if (!R->hasStackStorage() || !VR)
513 return true;
514
515 const VarDecl *VD = VR->getDecl();
516 if (!VD->hasAttr<CleanupAttr>())
517 return false; // CleanupAttr attaches destructors, which cause escaping.
518 return true;
519 }
520
521 static SmallVector<ProgramStateRef, 2>
updateOutParameters(ProgramStateRef State,const RetainSummary & Summ,const CallEvent & CE)522 updateOutParameters(ProgramStateRef State, const RetainSummary &Summ,
523 const CallEvent &CE) {
524
525 SVal L = CE.getReturnValue();
526
527 // Splitting is required to support out parameters,
528 // as out parameters might be created only on the "success" branch.
529 // We want to avoid eagerly splitting unless out parameters are actually
530 // needed.
531 bool SplitNecessary = false;
532 for (auto &P : Summ.getArgEffects())
533 if (P.second.getKind() == RetainedOutParameterOnNonZero ||
534 P.second.getKind() == RetainedOutParameterOnZero)
535 SplitNecessary = true;
536
537 ProgramStateRef AssumeNonZeroReturn = State;
538 ProgramStateRef AssumeZeroReturn = State;
539
540 if (SplitNecessary) {
541 if (!CE.getResultType()->isScalarType()) {
542 // Structures cannot be assumed. This probably deserves
543 // a compiler warning for invalid annotations.
544 return {State};
545 }
546 if (auto DL = L.getAs<DefinedOrUnknownSVal>()) {
547 AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true);
548 AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false);
549 }
550 }
551
552 for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) {
553 SVal ArgVal = CE.getArgSVal(idx);
554 ArgEffect AE = Summ.getArg(idx);
555
556 auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion());
557 if (!ArgRegion)
558 continue;
559
560 QualType PointeeTy = ArgRegion->getValueType();
561 SVal PointeeVal = State->getSVal(ArgRegion);
562 SymbolRef Pointee = PointeeVal.getAsLocSymbol();
563 if (!Pointee)
564 continue;
565
566 if (shouldEscapeRegion(ArgRegion))
567 continue;
568
569 auto makeNotOwnedParameter = [&](ProgramStateRef St) {
570 return setRefBinding(St, Pointee,
571 RefVal::makeNotOwned(AE.getObjKind(), PointeeTy));
572 };
573 auto makeOwnedParameter = [&](ProgramStateRef St) {
574 return setRefBinding(St, Pointee,
575 RefVal::makeOwned(ObjKind::OS, PointeeTy));
576 };
577
578 switch (AE.getKind()) {
579 case UnretainedOutParameter:
580 AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
581 AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
582 break;
583 case RetainedOutParameter:
584 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
585 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
586 break;
587 case RetainedOutParameterOnNonZero:
588 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
589 break;
590 case RetainedOutParameterOnZero:
591 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
592 break;
593 default:
594 break;
595 }
596 }
597
598 if (SplitNecessary) {
599 return {AssumeNonZeroReturn, AssumeZeroReturn};
600 } else {
601 assert(AssumeZeroReturn == AssumeNonZeroReturn);
602 return {AssumeZeroReturn};
603 }
604 }
605
checkSummary(const RetainSummary & Summ,const CallEvent & CallOrMsg,CheckerContext & C) const606 void RetainCountChecker::checkSummary(const RetainSummary &Summ,
607 const CallEvent &CallOrMsg,
608 CheckerContext &C) const {
609 ProgramStateRef state = C.getState();
610
611 // Evaluate the effect of the arguments.
612 RefVal::Kind hasErr = (RefVal::Kind) 0;
613 SourceRange ErrorRange;
614 SymbolRef ErrorSym = nullptr;
615
616 // Helper tag for providing diagnostics: indicate whether dealloc was sent
617 // at this location.
618 bool DeallocSent = false;
619
620 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
621 SVal V = CallOrMsg.getArgSVal(idx);
622
623 ArgEffect Effect = Summ.getArg(idx);
624 if (SymbolRef Sym = V.getAsLocSymbol()) {
625 if (const RefVal *T = getRefBinding(state, Sym)) {
626
627 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
628 Effect = ArgEffect(StopTrackingHard, ObjKind::OS);
629
630 state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
631 if (hasErr) {
632 ErrorRange = CallOrMsg.getArgSourceRange(idx);
633 ErrorSym = Sym;
634 break;
635 } else if (Effect.getKind() == Dealloc) {
636 DeallocSent = true;
637 }
638 }
639 }
640 }
641
642 // Evaluate the effect on the message receiver / `this` argument.
643 bool ReceiverIsTracked = false;
644 if (!hasErr) {
645 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
646 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
647 if (const RefVal *T = getRefBinding(state, Sym)) {
648 ReceiverIsTracked = true;
649 state = updateSymbol(state, Sym, *T,
650 Summ.getReceiverEffect(), hasErr, C);
651 if (hasErr) {
652 ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
653 ErrorSym = Sym;
654 } else if (Summ.getReceiverEffect().getKind() == Dealloc) {
655 DeallocSent = true;
656 }
657 }
658 }
659 } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
660 if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
661 if (const RefVal *T = getRefBinding(state, Sym)) {
662 state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
663 hasErr, C);
664 if (hasErr) {
665 ErrorRange = MCall->getOriginExpr()->getSourceRange();
666 ErrorSym = Sym;
667 }
668 }
669 }
670 }
671 }
672
673 // Process any errors.
674 if (hasErr) {
675 processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
676 return;
677 }
678
679 // Consult the summary for the return value.
680 RetEffect RE = Summ.getRetEffect();
681
682 if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
683 if (ReceiverIsTracked)
684 RE = getSummaryManager(C).getObjAllocRetEffect();
685 else
686 RE = RetEffect::MakeNoRet();
687 }
688
689 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
690 QualType ResultTy = CallOrMsg.getResultType();
691 if (RE.notOwned()) {
692 const Expr *Ex = CallOrMsg.getOriginExpr();
693 assert(Ex);
694 ResultTy = GetReturnType(Ex, C.getASTContext());
695 }
696 if (std::optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
697 state = setRefBinding(state, Sym, *updatedRefVal);
698 }
699
700 SmallVector<ProgramStateRef, 2> Out =
701 updateOutParameters(state, Summ, CallOrMsg);
702
703 for (ProgramStateRef St : Out) {
704 if (DeallocSent) {
705 C.addTransition(St, C.getPredecessor(), &getDeallocSentTag());
706 } else {
707 C.addTransition(St);
708 }
709 }
710 }
711
updateSymbol(ProgramStateRef state,SymbolRef sym,RefVal V,ArgEffect AE,RefVal::Kind & hasErr,CheckerContext & C) const712 ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
713 SymbolRef sym, RefVal V,
714 ArgEffect AE,
715 RefVal::Kind &hasErr,
716 CheckerContext &C) const {
717 bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
718 if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) {
719 switch (AE.getKind()) {
720 default:
721 break;
722 case IncRef:
723 AE = AE.withKind(DoNothing);
724 break;
725 case DecRef:
726 AE = AE.withKind(DoNothing);
727 break;
728 case DecRefAndStopTrackingHard:
729 AE = AE.withKind(StopTracking);
730 break;
731 }
732 }
733
734 // Handle all use-after-releases.
735 if (V.getKind() == RefVal::Released) {
736 V = V ^ RefVal::ErrorUseAfterRelease;
737 hasErr = V.getKind();
738 return setRefBinding(state, sym, V);
739 }
740
741 switch (AE.getKind()) {
742 case UnretainedOutParameter:
743 case RetainedOutParameter:
744 case RetainedOutParameterOnZero:
745 case RetainedOutParameterOnNonZero:
746 llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
747 "not have ref state.");
748
749 case Dealloc: // NB. we only need to add a note in a non-error case.
750 switch (V.getKind()) {
751 default:
752 llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
753 case RefVal::Owned:
754 // The object immediately transitions to the released state.
755 V = V ^ RefVal::Released;
756 V.clearCounts();
757 return setRefBinding(state, sym, V);
758 case RefVal::NotOwned:
759 V = V ^ RefVal::ErrorDeallocNotOwned;
760 hasErr = V.getKind();
761 break;
762 }
763 break;
764
765 case MayEscape:
766 if (V.getKind() == RefVal::Owned) {
767 V = V ^ RefVal::NotOwned;
768 break;
769 }
770
771 [[fallthrough]];
772
773 case DoNothing:
774 return state;
775
776 case Autorelease:
777 // Update the autorelease counts.
778 V = V.autorelease();
779 break;
780
781 case StopTracking:
782 case StopTrackingHard:
783 return removeRefBinding(state, sym);
784
785 case IncRef:
786 switch (V.getKind()) {
787 default:
788 llvm_unreachable("Invalid RefVal state for a retain.");
789 case RefVal::Owned:
790 case RefVal::NotOwned:
791 V = V + 1;
792 break;
793 }
794 break;
795
796 case DecRef:
797 case DecRefBridgedTransferred:
798 case DecRefAndStopTrackingHard:
799 switch (V.getKind()) {
800 default:
801 // case 'RefVal::Released' handled above.
802 llvm_unreachable("Invalid RefVal state for a release.");
803
804 case RefVal::Owned:
805 assert(V.getCount() > 0);
806 if (V.getCount() == 1) {
807 if (AE.getKind() == DecRefBridgedTransferred ||
808 V.getIvarAccessHistory() ==
809 RefVal::IvarAccessHistory::AccessedDirectly)
810 V = V ^ RefVal::NotOwned;
811 else
812 V = V ^ RefVal::Released;
813 } else if (AE.getKind() == DecRefAndStopTrackingHard) {
814 return removeRefBinding(state, sym);
815 }
816
817 V = V - 1;
818 break;
819
820 case RefVal::NotOwned:
821 if (V.getCount() > 0) {
822 if (AE.getKind() == DecRefAndStopTrackingHard)
823 return removeRefBinding(state, sym);
824 V = V - 1;
825 } else if (V.getIvarAccessHistory() ==
826 RefVal::IvarAccessHistory::AccessedDirectly) {
827 // Assume that the instance variable was holding on the object at
828 // +1, and we just didn't know.
829 if (AE.getKind() == DecRefAndStopTrackingHard)
830 return removeRefBinding(state, sym);
831 V = V.releaseViaIvar() ^ RefVal::Released;
832 } else {
833 V = V ^ RefVal::ErrorReleaseNotOwned;
834 hasErr = V.getKind();
835 }
836 break;
837 }
838 break;
839 }
840 return setRefBinding(state, sym, V);
841 }
842
843 const RefCountBug &
errorKindToBugKind(RefVal::Kind ErrorKind,SymbolRef Sym) const844 RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
845 SymbolRef Sym) const {
846 switch (ErrorKind) {
847 case RefVal::ErrorUseAfterRelease:
848 return *UseAfterRelease;
849 case RefVal::ErrorReleaseNotOwned:
850 return *ReleaseNotOwned;
851 case RefVal::ErrorDeallocNotOwned:
852 if (Sym->getType()->getPointeeCXXRecordDecl())
853 return *FreeNotOwned;
854 return *DeallocNotOwned;
855 default:
856 llvm_unreachable("Unhandled error.");
857 }
858 }
859
processNonLeakError(ProgramStateRef St,SourceRange ErrorRange,RefVal::Kind ErrorKind,SymbolRef Sym,CheckerContext & C) const860 void RetainCountChecker::processNonLeakError(ProgramStateRef St,
861 SourceRange ErrorRange,
862 RefVal::Kind ErrorKind,
863 SymbolRef Sym,
864 CheckerContext &C) const {
865 // HACK: Ignore retain-count issues on values accessed through ivars,
866 // because of cases like this:
867 // [_contentView retain];
868 // [_contentView removeFromSuperview];
869 // [self addSubview:_contentView]; // invalidates 'self'
870 // [_contentView release];
871 if (const RefVal *RV = getRefBinding(St, Sym))
872 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
873 return;
874
875 ExplodedNode *N = C.generateErrorNode(St);
876 if (!N)
877 return;
878
879 auto report = std::make_unique<RefCountReport>(
880 errorKindToBugKind(ErrorKind, Sym),
881 C.getASTContext().getLangOpts(), N, Sym);
882 report->addRange(ErrorRange);
883 C.emitReport(std::move(report));
884 }
885
886 //===----------------------------------------------------------------------===//
887 // Handle the return values of retain-count-related functions.
888 //===----------------------------------------------------------------------===//
889
evalCall(const CallEvent & Call,CheckerContext & C) const890 bool RetainCountChecker::evalCall(const CallEvent &Call,
891 CheckerContext &C) const {
892 ProgramStateRef state = C.getState();
893 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
894 if (!FD)
895 return false;
896
897 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
898 if (!CE)
899 return false;
900
901 RetainSummaryManager &SmrMgr = getSummaryManager(C);
902 QualType ResultTy = Call.getResultType();
903
904 // See if the function has 'rc_ownership_trusted_implementation'
905 // annotate attribute. If it does, we will not inline it.
906 bool hasTrustedImplementationAnnotation = false;
907
908 const LocationContext *LCtx = C.getLocationContext();
909
910 using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
911 std::optional<BehaviorSummary> BSmr =
912 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
913
914 // See if it's one of the specific functions we know how to eval.
915 if (!BSmr)
916 return false;
917
918 // Bind the return value.
919 if (BSmr == BehaviorSummary::Identity ||
920 BSmr == BehaviorSummary::IdentityOrZero ||
921 BSmr == BehaviorSummary::IdentityThis) {
922
923 const Expr *BindReturnTo =
924 (BSmr == BehaviorSummary::IdentityThis)
925 ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
926 : CE->getArg(0);
927 SVal RetVal = state->getSVal(BindReturnTo, LCtx);
928
929 // If the receiver is unknown or the function has
930 // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
931 // return value.
932 // FIXME: this branch is very strange.
933 if (RetVal.isUnknown() ||
934 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
935 SValBuilder &SVB = C.getSValBuilder();
936 RetVal =
937 SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
938 }
939
940 // Bind the value.
941 state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
942
943 if (BSmr == BehaviorSummary::IdentityOrZero) {
944 // Add a branch where the output is zero.
945 ProgramStateRef NullOutputState = C.getState();
946
947 // Assume that output is zero on the other branch.
948 NullOutputState = NullOutputState->BindExpr(
949 CE, LCtx, C.getSValBuilder().makeNullWithType(ResultTy),
950 /*Invalidate=*/false);
951 C.addTransition(NullOutputState, &getCastFailTag());
952
953 // And on the original branch assume that both input and
954 // output are non-zero.
955 if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
956 state = state->assume(*L, /*assumption=*/true);
957
958 }
959 }
960
961 C.addTransition(state);
962 return true;
963 }
964
processReturn(const ReturnStmt * S,CheckerContext & C) const965 ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
966 CheckerContext &C) const {
967 ExplodedNode *Pred = C.getPredecessor();
968
969 // Only adjust the reference count if this is the top-level call frame,
970 // and not the result of inlining. In the future, we should do
971 // better checking even for inlined calls, and see if they match
972 // with their expected semantics (e.g., the method should return a retained
973 // object, etc.).
974 if (!C.inTopFrame())
975 return Pred;
976
977 if (!S)
978 return Pred;
979
980 const Expr *RetE = S->getRetValue();
981 if (!RetE)
982 return Pred;
983
984 ProgramStateRef state = C.getState();
985 // We need to dig down to the symbolic base here because various
986 // custom allocators do sometimes return the symbol with an offset.
987 SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext())
988 .getAsLocSymbol(/*IncludeBaseRegions=*/true);
989 if (!Sym)
990 return Pred;
991
992 // Get the reference count binding (if any).
993 const RefVal *T = getRefBinding(state, Sym);
994 if (!T)
995 return Pred;
996
997 // Change the reference count.
998 RefVal X = *T;
999
1000 switch (X.getKind()) {
1001 case RefVal::Owned: {
1002 unsigned cnt = X.getCount();
1003 assert(cnt > 0);
1004 X.setCount(cnt - 1);
1005 X = X ^ RefVal::ReturnedOwned;
1006 break;
1007 }
1008
1009 case RefVal::NotOwned: {
1010 unsigned cnt = X.getCount();
1011 if (cnt) {
1012 X.setCount(cnt - 1);
1013 X = X ^ RefVal::ReturnedOwned;
1014 } else {
1015 X = X ^ RefVal::ReturnedNotOwned;
1016 }
1017 break;
1018 }
1019
1020 default:
1021 return Pred;
1022 }
1023
1024 // Update the binding.
1025 state = setRefBinding(state, Sym, X);
1026 Pred = C.addTransition(state);
1027
1028 // At this point we have updated the state properly.
1029 // Everything after this is merely checking to see if the return value has
1030 // been over- or under-retained.
1031
1032 // Did we cache out?
1033 if (!Pred)
1034 return nullptr;
1035
1036 // Update the autorelease counts.
1037 static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease");
1038 state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S);
1039
1040 // Have we generated a sink node?
1041 if (!state)
1042 return nullptr;
1043
1044 // Get the updated binding.
1045 T = getRefBinding(state, Sym);
1046 assert(T);
1047 X = *T;
1048
1049 // Consult the summary of the enclosing method.
1050 RetainSummaryManager &Summaries = getSummaryManager(C);
1051 const Decl *CD = &Pred->getCodeDecl();
1052 RetEffect RE = RetEffect::MakeNoRet();
1053
1054 // FIXME: What is the convention for blocks? Is there one?
1055 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
1056 const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD));
1057 RE = Summ->getRetEffect();
1058 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
1059 if (!isa<CXXMethodDecl>(FD)) {
1060 const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD));
1061 RE = Summ->getRetEffect();
1062 }
1063 }
1064
1065 return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
1066 }
1067
checkReturnWithRetEffect(const ReturnStmt * S,CheckerContext & C,ExplodedNode * Pred,RetEffect RE,RefVal X,SymbolRef Sym,ProgramStateRef state) const1068 ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
1069 CheckerContext &C,
1070 ExplodedNode *Pred,
1071 RetEffect RE, RefVal X,
1072 SymbolRef Sym,
1073 ProgramStateRef state) const {
1074 // HACK: Ignore retain-count issues on values accessed through ivars,
1075 // because of cases like this:
1076 // [_contentView retain];
1077 // [_contentView removeFromSuperview];
1078 // [self addSubview:_contentView]; // invalidates 'self'
1079 // [_contentView release];
1080 if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1081 return Pred;
1082
1083 // Any leaks or other errors?
1084 if (X.isReturnedOwned() && X.getCount() == 0) {
1085 if (RE.getKind() != RetEffect::NoRet) {
1086 if (!RE.isOwned()) {
1087
1088 // The returning type is a CF, we expect the enclosing method should
1089 // return ownership.
1090 X = X ^ RefVal::ErrorLeakReturned;
1091
1092 // Generate an error node.
1093 state = setRefBinding(state, Sym, X);
1094
1095 static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak");
1096 ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
1097 if (N) {
1098 const LangOptions &LOpts = C.getASTContext().getLangOpts();
1099 auto R =
1100 std::make_unique<RefLeakReport>(*LeakAtReturn, LOpts, N, Sym, C);
1101 C.emitReport(std::move(R));
1102 }
1103 return N;
1104 }
1105 }
1106 } else if (X.isReturnedNotOwned()) {
1107 if (RE.isOwned()) {
1108 if (X.getIvarAccessHistory() ==
1109 RefVal::IvarAccessHistory::AccessedDirectly) {
1110 // Assume the method was trying to transfer a +1 reference from a
1111 // strong ivar to the caller.
1112 state = setRefBinding(state, Sym,
1113 X.releaseViaIvar() ^ RefVal::ReturnedOwned);
1114 } else {
1115 // Trying to return a not owned object to a caller expecting an
1116 // owned object.
1117 state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
1118
1119 static CheckerProgramPointTag
1120 ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned");
1121
1122 ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
1123 if (N) {
1124 auto R = std::make_unique<RefCountReport>(
1125 *ReturnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
1126 C.emitReport(std::move(R));
1127 }
1128 return N;
1129 }
1130 }
1131 }
1132 return Pred;
1133 }
1134
1135 //===----------------------------------------------------------------------===//
1136 // Check various ways a symbol can be invalidated.
1137 //===----------------------------------------------------------------------===//
1138
checkBind(SVal loc,SVal val,const Stmt * S,CheckerContext & C) const1139 void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
1140 CheckerContext &C) const {
1141 ProgramStateRef state = C.getState();
1142 const MemRegion *MR = loc.getAsRegion();
1143
1144 // Find all symbols referenced by 'val' that we are tracking
1145 // and stop tracking them.
1146 if (MR && shouldEscapeRegion(MR)) {
1147 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
1148 C.addTransition(state);
1149 }
1150 }
1151
evalAssume(ProgramStateRef state,SVal Cond,bool Assumption) const1152 ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
1153 SVal Cond,
1154 bool Assumption) const {
1155 // FIXME: We may add to the interface of evalAssume the list of symbols
1156 // whose assumptions have changed. For now we just iterate through the
1157 // bindings and check if any of the tracked symbols are NULL. This isn't
1158 // too bad since the number of symbols we will track in practice are
1159 // probably small and evalAssume is only called at branches and a few
1160 // other places.
1161 RefBindingsTy B = state->get<RefBindings>();
1162
1163 if (B.isEmpty())
1164 return state;
1165
1166 bool changed = false;
1167 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
1168 ConstraintManager &CMgr = state->getConstraintManager();
1169
1170 for (auto &I : B) {
1171 // Check if the symbol is null stop tracking the symbol.
1172 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
1173 if (AllocFailed.isConstrainedTrue()) {
1174 changed = true;
1175 B = RefBFactory.remove(B, I.first);
1176 }
1177 }
1178
1179 if (changed)
1180 state = state->set<RefBindings>(B);
1181
1182 return state;
1183 }
1184
checkRegionChanges(ProgramStateRef state,const InvalidatedSymbols * invalidated,ArrayRef<const MemRegion * > ExplicitRegions,ArrayRef<const MemRegion * > Regions,const LocationContext * LCtx,const CallEvent * Call) const1185 ProgramStateRef RetainCountChecker::checkRegionChanges(
1186 ProgramStateRef state, const InvalidatedSymbols *invalidated,
1187 ArrayRef<const MemRegion *> ExplicitRegions,
1188 ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
1189 const CallEvent *Call) const {
1190 if (!invalidated)
1191 return state;
1192
1193 llvm::SmallPtrSet<SymbolRef, 8> AllowedSymbols;
1194
1195 for (const MemRegion *I : ExplicitRegions)
1196 if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
1197 AllowedSymbols.insert(SR->getSymbol());
1198
1199 for (SymbolRef sym : *invalidated) {
1200 if (AllowedSymbols.count(sym))
1201 continue;
1202 // Remove any existing reference-count binding.
1203 state = removeRefBinding(state, sym);
1204 }
1205 return state;
1206 }
1207
1208 ProgramStateRef
handleAutoreleaseCounts(ProgramStateRef state,ExplodedNode * Pred,const ProgramPointTag * Tag,CheckerContext & Ctx,SymbolRef Sym,RefVal V,const ReturnStmt * S) const1209 RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
1210 ExplodedNode *Pred,
1211 const ProgramPointTag *Tag,
1212 CheckerContext &Ctx,
1213 SymbolRef Sym,
1214 RefVal V,
1215 const ReturnStmt *S) const {
1216 unsigned ACnt = V.getAutoreleaseCount();
1217
1218 // No autorelease counts? Nothing to be done.
1219 if (!ACnt)
1220 return state;
1221
1222 unsigned Cnt = V.getCount();
1223
1224 // FIXME: Handle sending 'autorelease' to already released object.
1225
1226 if (V.getKind() == RefVal::ReturnedOwned)
1227 ++Cnt;
1228
1229 // If we would over-release here, but we know the value came from an ivar,
1230 // assume it was a strong ivar that's just been relinquished.
1231 if (ACnt > Cnt &&
1232 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
1233 V = V.releaseViaIvar();
1234 --ACnt;
1235 }
1236
1237 if (ACnt <= Cnt) {
1238 if (ACnt == Cnt) {
1239 V.clearCounts();
1240 if (V.getKind() == RefVal::ReturnedOwned) {
1241 V = V ^ RefVal::ReturnedNotOwned;
1242 } else {
1243 V = V ^ RefVal::NotOwned;
1244 }
1245 } else {
1246 V.setCount(V.getCount() - ACnt);
1247 V.setAutoreleaseCount(0);
1248 }
1249 return setRefBinding(state, Sym, V);
1250 }
1251
1252 // HACK: Ignore retain-count issues on values accessed through ivars,
1253 // because of cases like this:
1254 // [_contentView retain];
1255 // [_contentView removeFromSuperview];
1256 // [self addSubview:_contentView]; // invalidates 'self'
1257 // [_contentView release];
1258 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1259 return state;
1260
1261 // Woah! More autorelease counts then retain counts left.
1262 // Emit hard error.
1263 V = V ^ RefVal::ErrorOverAutorelease;
1264 state = setRefBinding(state, Sym, V);
1265
1266 ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
1267 if (N) {
1268 SmallString<128> sbuf;
1269 llvm::raw_svector_ostream os(sbuf);
1270 os << "Object was autoreleased ";
1271 if (V.getAutoreleaseCount() > 1)
1272 os << V.getAutoreleaseCount() << " times but the object ";
1273 else
1274 os << "but ";
1275 os << "has a +" << V.getCount() << " retain count";
1276
1277 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
1278 auto R = std::make_unique<RefCountReport>(*OverAutorelease, LOpts, N, Sym,
1279 os.str());
1280 Ctx.emitReport(std::move(R));
1281 }
1282
1283 return nullptr;
1284 }
1285
1286 ProgramStateRef
handleSymbolDeath(ProgramStateRef state,SymbolRef sid,RefVal V,SmallVectorImpl<SymbolRef> & Leaked) const1287 RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
1288 SymbolRef sid, RefVal V,
1289 SmallVectorImpl<SymbolRef> &Leaked) const {
1290 bool hasLeak;
1291
1292 // HACK: Ignore retain-count issues on values accessed through ivars,
1293 // because of cases like this:
1294 // [_contentView retain];
1295 // [_contentView removeFromSuperview];
1296 // [self addSubview:_contentView]; // invalidates 'self'
1297 // [_contentView release];
1298 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1299 hasLeak = false;
1300 else if (V.isOwned())
1301 hasLeak = true;
1302 else if (V.isNotOwned() || V.isReturnedOwned())
1303 hasLeak = (V.getCount() > 0);
1304 else
1305 hasLeak = false;
1306
1307 if (!hasLeak)
1308 return removeRefBinding(state, sid);
1309
1310 Leaked.push_back(sid);
1311 return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
1312 }
1313
1314 ExplodedNode *
processLeaks(ProgramStateRef state,SmallVectorImpl<SymbolRef> & Leaked,CheckerContext & Ctx,ExplodedNode * Pred) const1315 RetainCountChecker::processLeaks(ProgramStateRef state,
1316 SmallVectorImpl<SymbolRef> &Leaked,
1317 CheckerContext &Ctx,
1318 ExplodedNode *Pred) const {
1319 // Generate an intermediate node representing the leak point.
1320 ExplodedNode *N = Ctx.addTransition(state, Pred);
1321 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
1322
1323 if (N) {
1324 for (SymbolRef L : Leaked) {
1325 const RefCountBug &BT = Pred ? *LeakWithinFunction : *LeakAtReturn;
1326 Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
1327 }
1328 }
1329
1330 return N;
1331 }
1332
checkBeginFunction(CheckerContext & Ctx) const1333 void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
1334 if (!Ctx.inTopFrame())
1335 return;
1336
1337 RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
1338 const LocationContext *LCtx = Ctx.getLocationContext();
1339 const Decl *D = LCtx->getDecl();
1340 std::optional<AnyCall> C = AnyCall::forDecl(D);
1341
1342 if (!C || SmrMgr.isTrustedReferenceCountImplementation(D))
1343 return;
1344
1345 ProgramStateRef state = Ctx.getState();
1346 const RetainSummary *FunctionSummary = SmrMgr.getSummary(*C);
1347 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
1348
1349 for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) {
1350 const ParmVarDecl *Param = C->parameters()[idx];
1351 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
1352
1353 QualType Ty = Param->getType();
1354 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
1355 if (AE) {
1356 ObjKind K = AE->getObjKind();
1357 if (K == ObjKind::Generalized || K == ObjKind::OS ||
1358 (TrackNSCFStartParam && (K == ObjKind::ObjC || K == ObjKind::CF))) {
1359 RefVal NewVal = AE->getKind() == DecRef ? RefVal::makeOwned(K, Ty)
1360 : RefVal::makeNotOwned(K, Ty);
1361 state = setRefBinding(state, Sym, NewVal);
1362 }
1363 }
1364 }
1365
1366 Ctx.addTransition(state);
1367 }
1368
checkEndFunction(const ReturnStmt * RS,CheckerContext & Ctx) const1369 void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
1370 CheckerContext &Ctx) const {
1371 ExplodedNode *Pred = processReturn(RS, Ctx);
1372
1373 // Created state cached out.
1374 if (!Pred) {
1375 return;
1376 }
1377
1378 ProgramStateRef state = Pred->getState();
1379 RefBindingsTy B = state->get<RefBindings>();
1380
1381 // Don't process anything within synthesized bodies.
1382 const LocationContext *LCtx = Pred->getLocationContext();
1383 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
1384 assert(!LCtx->inTopFrame());
1385 return;
1386 }
1387
1388 for (auto &I : B) {
1389 state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx,
1390 I.first, I.second);
1391 if (!state)
1392 return;
1393 }
1394
1395 // If the current LocationContext has a parent, don't check for leaks.
1396 // We will do that later.
1397 // FIXME: we should instead check for imbalances of the retain/releases,
1398 // and suggest annotations.
1399 if (LCtx->getParent())
1400 return;
1401
1402 B = state->get<RefBindings>();
1403 SmallVector<SymbolRef, 10> Leaked;
1404
1405 for (auto &I : B)
1406 state = handleSymbolDeath(state, I.first, I.second, Leaked);
1407
1408 processLeaks(state, Leaked, Ctx, Pred);
1409 }
1410
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const1411 void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1412 CheckerContext &C) const {
1413 ExplodedNode *Pred = C.getPredecessor();
1414
1415 ProgramStateRef state = C.getState();
1416 SmallVector<SymbolRef, 10> Leaked;
1417
1418 // Update counts from autorelease pools
1419 for (const auto &I: state->get<RefBindings>()) {
1420 SymbolRef Sym = I.first;
1421 if (SymReaper.isDead(Sym)) {
1422 static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease");
1423 const RefVal &V = I.second;
1424 state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V);
1425 if (!state)
1426 return;
1427
1428 // Fetch the new reference count from the state, and use it to handle
1429 // this symbol.
1430 state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
1431 }
1432 }
1433
1434 if (Leaked.empty()) {
1435 C.addTransition(state);
1436 return;
1437 }
1438
1439 Pred = processLeaks(state, Leaked, C, Pred);
1440
1441 // Did we cache out?
1442 if (!Pred)
1443 return;
1444
1445 // Now generate a new node that nukes the old bindings.
1446 // The only bindings left at this point are the leaked symbols.
1447 RefBindingsTy::Factory &F = state->get_context<RefBindings>();
1448 RefBindingsTy B = state->get<RefBindings>();
1449
1450 for (SymbolRef L : Leaked)
1451 B = F.remove(B, L);
1452
1453 state = state->set<RefBindings>(B);
1454 C.addTransition(state, Pred);
1455 }
1456
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const1457 void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
1458 const char *NL, const char *Sep) const {
1459
1460 RefBindingsTy B = State->get<RefBindings>();
1461
1462 if (B.isEmpty())
1463 return;
1464
1465 Out << Sep << NL;
1466
1467 for (auto &I : B) {
1468 Out << I.first << " : ";
1469 I.second.print(Out);
1470 Out << NL;
1471 }
1472 }
1473
1474 //===----------------------------------------------------------------------===//
1475 // Checker registration.
1476 //===----------------------------------------------------------------------===//
1477
1478 std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::DeallocSentTag;
1479 std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::CastFailTag;
1480
registerRetainCountBase(CheckerManager & Mgr)1481 void ento::registerRetainCountBase(CheckerManager &Mgr) {
1482 auto *Chk = Mgr.registerChecker<RetainCountChecker>();
1483 Chk->DeallocSentTag =
1484 std::make_unique<CheckerProgramPointTag>(Chk, "DeallocSent");
1485 Chk->CastFailTag =
1486 std::make_unique<CheckerProgramPointTag>(Chk, "DynamicCastFail");
1487 }
1488
shouldRegisterRetainCountBase(const CheckerManager & mgr)1489 bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) {
1490 return true;
1491 }
registerRetainCountChecker(CheckerManager & Mgr)1492 void ento::registerRetainCountChecker(CheckerManager &Mgr) {
1493 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1494 Chk->TrackObjCAndCFObjects = true;
1495 Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
1496 Mgr.getCurrentCheckerName(), "TrackNSCFStartParam");
1497
1498 #define INIT_BUGTYPE(KIND) \
1499 Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \
1500 RefCountBug::KIND);
1501 // TODO: Ideally, we should have a checker for each of these bug types.
1502 INIT_BUGTYPE(UseAfterRelease)
1503 INIT_BUGTYPE(ReleaseNotOwned)
1504 INIT_BUGTYPE(DeallocNotOwned)
1505 INIT_BUGTYPE(FreeNotOwned)
1506 INIT_BUGTYPE(OverAutorelease)
1507 INIT_BUGTYPE(ReturnNotOwnedForOwned)
1508 INIT_BUGTYPE(LeakWithinFunction)
1509 INIT_BUGTYPE(LeakAtReturn)
1510 #undef INIT_BUGTYPE
1511 }
1512
shouldRegisterRetainCountChecker(const CheckerManager & mgr)1513 bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) {
1514 return true;
1515 }
1516
registerOSObjectRetainCountChecker(CheckerManager & Mgr)1517 void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
1518 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1519 Chk->TrackOSObjects = true;
1520
1521 // FIXME: We want bug reports to always have the same checker name associated
1522 // with them, yet here, if RetainCountChecker is disabled but
1523 // OSObjectRetainCountChecker is enabled, the checker names will be different.
1524 // This hack will make it so that the checker name depends on which checker is
1525 // enabled rather than on the registration order.
1526 // For the most part, we want **non-hidden checkers** to be associated with
1527 // diagnostics, and **hidden checker options** with the fine-tuning of
1528 // modeling. Following this logic, OSObjectRetainCountChecker should be the
1529 // latter, but we can't just remove it for backward compatibility reasons.
1530 #define LAZY_INIT_BUGTYPE(KIND) \
1531 if (!Chk->KIND) \
1532 Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \
1533 RefCountBug::KIND);
1534 LAZY_INIT_BUGTYPE(UseAfterRelease)
1535 LAZY_INIT_BUGTYPE(ReleaseNotOwned)
1536 LAZY_INIT_BUGTYPE(DeallocNotOwned)
1537 LAZY_INIT_BUGTYPE(FreeNotOwned)
1538 LAZY_INIT_BUGTYPE(OverAutorelease)
1539 LAZY_INIT_BUGTYPE(ReturnNotOwnedForOwned)
1540 LAZY_INIT_BUGTYPE(LeakWithinFunction)
1541 LAZY_INIT_BUGTYPE(LeakAtReturn)
1542 #undef LAZY_INIT_BUGTYPE
1543 }
1544
shouldRegisterOSObjectRetainCountChecker(const CheckerManager & mgr)1545 bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) {
1546 return true;
1547 }
1548