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