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