170c2ee30SGeorge Karpenkov //==-- RetainCountChecker.cpp - Checks for leaks and other issues -*- C++ -*--//
270c2ee30SGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
670c2ee30SGeorge Karpenkov //
770c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
870c2ee30SGeorge Karpenkov //
970c2ee30SGeorge Karpenkov //  This file defines the methods for RetainCountChecker, which implements
1070c2ee30SGeorge Karpenkov //  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
1170c2ee30SGeorge Karpenkov //
1270c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
1370c2ee30SGeorge Karpenkov 
1470c2ee30SGeorge Karpenkov #include "RetainCountChecker.h"
155192783bSKirstóf Umann #include "clang/StaticAnalyzer/Core/Checker.h"
166fdd2bd5SGeorge Karpenkov #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
1770c2ee30SGeorge Karpenkov 
1870c2ee30SGeorge Karpenkov using namespace clang;
1970c2ee30SGeorge Karpenkov using namespace ento;
2070c2ee30SGeorge Karpenkov using namespace retaincountchecker;
2170c2ee30SGeorge Karpenkov 
2270c2ee30SGeorge Karpenkov REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
2370c2ee30SGeorge Karpenkov 
2470c2ee30SGeorge Karpenkov namespace clang {
2570c2ee30SGeorge Karpenkov namespace ento {
2670c2ee30SGeorge Karpenkov namespace retaincountchecker {
2770c2ee30SGeorge Karpenkov 
getRefBinding(ProgramStateRef State,SymbolRef Sym)2870c2ee30SGeorge Karpenkov const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) {
2970c2ee30SGeorge Karpenkov   return State->get<RefBindings>(Sym);
3070c2ee30SGeorge Karpenkov }
3170c2ee30SGeorge Karpenkov 
322c2d0b6eSGeorge Karpenkov } // end namespace retaincountchecker
332c2d0b6eSGeorge Karpenkov } // end namespace ento
342c2d0b6eSGeorge Karpenkov } // end namespace clang
352c2d0b6eSGeorge Karpenkov 
setRefBinding(ProgramStateRef State,SymbolRef Sym,RefVal Val)36f153cdfbSGeorge Karpenkov static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym,
3770c2ee30SGeorge Karpenkov                                      RefVal Val) {
38d5ef0d2aSGeorge Karpenkov   assert(Sym != nullptr);
3970c2ee30SGeorge Karpenkov   return State->set<RefBindings>(Sym, Val);
4070c2ee30SGeorge Karpenkov }
4170c2ee30SGeorge Karpenkov 
removeRefBinding(ProgramStateRef State,SymbolRef Sym)42f153cdfbSGeorge Karpenkov static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) {
4370c2ee30SGeorge Karpenkov   return State->remove<RefBindings>(Sym);
4470c2ee30SGeorge Karpenkov }
4570c2ee30SGeorge Karpenkov 
print(raw_ostream & Out) const4670c2ee30SGeorge Karpenkov void RefVal::print(raw_ostream &Out) const {
4770c2ee30SGeorge Karpenkov   if (!T.isNull())
48*cfb81690SNathan James     Out << "Tracked " << T << " | ";
4970c2ee30SGeorge Karpenkov 
5070c2ee30SGeorge Karpenkov   switch (getKind()) {
5170c2ee30SGeorge Karpenkov     default: llvm_unreachable("Invalid RefVal kind");
5270c2ee30SGeorge Karpenkov     case Owned: {
5370c2ee30SGeorge Karpenkov       Out << "Owned";
5470c2ee30SGeorge Karpenkov       unsigned cnt = getCount();
5570c2ee30SGeorge Karpenkov       if (cnt) Out << " (+ " << cnt << ")";
5670c2ee30SGeorge Karpenkov       break;
5770c2ee30SGeorge Karpenkov     }
5870c2ee30SGeorge Karpenkov 
5970c2ee30SGeorge Karpenkov     case NotOwned: {
6070c2ee30SGeorge Karpenkov       Out << "NotOwned";
6170c2ee30SGeorge Karpenkov       unsigned cnt = getCount();
6270c2ee30SGeorge Karpenkov       if (cnt) Out << " (+ " << cnt << ")";
6370c2ee30SGeorge Karpenkov       break;
6470c2ee30SGeorge Karpenkov     }
6570c2ee30SGeorge Karpenkov 
6670c2ee30SGeorge Karpenkov     case ReturnedOwned: {
6770c2ee30SGeorge Karpenkov       Out << "ReturnedOwned";
6870c2ee30SGeorge Karpenkov       unsigned cnt = getCount();
6970c2ee30SGeorge Karpenkov       if (cnt) Out << " (+ " << cnt << ")";
7070c2ee30SGeorge Karpenkov       break;
7170c2ee30SGeorge Karpenkov     }
7270c2ee30SGeorge Karpenkov 
7370c2ee30SGeorge Karpenkov     case ReturnedNotOwned: {
7470c2ee30SGeorge Karpenkov       Out << "ReturnedNotOwned";
7570c2ee30SGeorge Karpenkov       unsigned cnt = getCount();
7670c2ee30SGeorge Karpenkov       if (cnt) Out << " (+ " << cnt << ")";
7770c2ee30SGeorge Karpenkov       break;
7870c2ee30SGeorge Karpenkov     }
7970c2ee30SGeorge Karpenkov 
8070c2ee30SGeorge Karpenkov     case Released:
8170c2ee30SGeorge Karpenkov       Out << "Released";
8270c2ee30SGeorge Karpenkov       break;
8370c2ee30SGeorge Karpenkov 
8470c2ee30SGeorge Karpenkov     case ErrorDeallocNotOwned:
8570c2ee30SGeorge Karpenkov       Out << "-dealloc (not-owned)";
8670c2ee30SGeorge Karpenkov       break;
8770c2ee30SGeorge Karpenkov 
8870c2ee30SGeorge Karpenkov     case ErrorLeak:
8970c2ee30SGeorge Karpenkov       Out << "Leaked";
9070c2ee30SGeorge Karpenkov       break;
9170c2ee30SGeorge Karpenkov 
9270c2ee30SGeorge Karpenkov     case ErrorLeakReturned:
9370c2ee30SGeorge Karpenkov       Out << "Leaked (Bad naming)";
9470c2ee30SGeorge Karpenkov       break;
9570c2ee30SGeorge Karpenkov 
9670c2ee30SGeorge Karpenkov     case ErrorUseAfterRelease:
9770c2ee30SGeorge Karpenkov       Out << "Use-After-Release [ERROR]";
9870c2ee30SGeorge Karpenkov       break;
9970c2ee30SGeorge Karpenkov 
10070c2ee30SGeorge Karpenkov     case ErrorReleaseNotOwned:
10170c2ee30SGeorge Karpenkov       Out << "Release of Not-Owned [ERROR]";
10270c2ee30SGeorge Karpenkov       break;
10370c2ee30SGeorge Karpenkov 
10470c2ee30SGeorge Karpenkov     case RefVal::ErrorOverAutorelease:
10570c2ee30SGeorge Karpenkov       Out << "Over-autoreleased";
10670c2ee30SGeorge Karpenkov       break;
10770c2ee30SGeorge Karpenkov 
10870c2ee30SGeorge Karpenkov     case RefVal::ErrorReturnedNotOwned:
10970c2ee30SGeorge Karpenkov       Out << "Non-owned object returned instead of owned";
11070c2ee30SGeorge Karpenkov       break;
11170c2ee30SGeorge Karpenkov   }
11270c2ee30SGeorge Karpenkov 
11370c2ee30SGeorge Karpenkov   switch (getIvarAccessHistory()) {
11470c2ee30SGeorge Karpenkov   case IvarAccessHistory::None:
11570c2ee30SGeorge Karpenkov     break;
11670c2ee30SGeorge Karpenkov   case IvarAccessHistory::AccessedDirectly:
11770c2ee30SGeorge Karpenkov     Out << " [direct ivar access]";
11870c2ee30SGeorge Karpenkov     break;
11970c2ee30SGeorge Karpenkov   case IvarAccessHistory::ReleasedAfterDirectAccess:
12070c2ee30SGeorge Karpenkov     Out << " [released after direct ivar access]";
12170c2ee30SGeorge Karpenkov   }
12270c2ee30SGeorge Karpenkov 
12370c2ee30SGeorge Karpenkov   if (ACnt) {
12470c2ee30SGeorge Karpenkov     Out << " [autorelease -" << ACnt << ']';
12570c2ee30SGeorge Karpenkov   }
12670c2ee30SGeorge Karpenkov }
12770c2ee30SGeorge Karpenkov 
12870c2ee30SGeorge Karpenkov namespace {
12970c2ee30SGeorge Karpenkov class StopTrackingCallback final : public SymbolVisitor {
13070c2ee30SGeorge Karpenkov   ProgramStateRef state;
13170c2ee30SGeorge Karpenkov public:
StopTrackingCallback(ProgramStateRef st)13270c2ee30SGeorge Karpenkov   StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
getState() const13370c2ee30SGeorge Karpenkov   ProgramStateRef getState() const { return state; }
13470c2ee30SGeorge Karpenkov 
VisitSymbol(SymbolRef sym)13570c2ee30SGeorge Karpenkov   bool VisitSymbol(SymbolRef sym) override {
136f153cdfbSGeorge Karpenkov     state = removeRefBinding(state, sym);
13770c2ee30SGeorge Karpenkov     return true;
13870c2ee30SGeorge Karpenkov   }
13970c2ee30SGeorge Karpenkov };
14070c2ee30SGeorge Karpenkov } // end anonymous namespace
14170c2ee30SGeorge Karpenkov 
14270c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
14370c2ee30SGeorge Karpenkov // Handle statements that may have an effect on refcounts.
14470c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
14570c2ee30SGeorge Karpenkov 
checkPostStmt(const BlockExpr * BE,CheckerContext & C) const14670c2ee30SGeorge Karpenkov void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
14770c2ee30SGeorge Karpenkov                                        CheckerContext &C) const {
14870c2ee30SGeorge Karpenkov 
14970c2ee30SGeorge Karpenkov   // Scan the BlockDecRefExprs for any object the retain count checker
15070c2ee30SGeorge Karpenkov   // may be tracking.
15170c2ee30SGeorge Karpenkov   if (!BE->getBlockDecl()->hasCaptures())
15270c2ee30SGeorge Karpenkov     return;
15370c2ee30SGeorge Karpenkov 
15470c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
15570c2ee30SGeorge Karpenkov   auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
15670c2ee30SGeorge Karpenkov 
15770c2ee30SGeorge Karpenkov   BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
15870c2ee30SGeorge Karpenkov                                             E = R->referenced_vars_end();
15970c2ee30SGeorge Karpenkov 
16070c2ee30SGeorge Karpenkov   if (I == E)
16170c2ee30SGeorge Karpenkov     return;
16270c2ee30SGeorge Karpenkov 
16370c2ee30SGeorge Karpenkov   // FIXME: For now we invalidate the tracking of all symbols passed to blocks
16470c2ee30SGeorge Karpenkov   // via captured variables, even though captured variables result in a copy
16570c2ee30SGeorge Karpenkov   // and in implicit increment/decrement of a retain count.
16670c2ee30SGeorge Karpenkov   SmallVector<const MemRegion*, 10> Regions;
16770c2ee30SGeorge Karpenkov   const LocationContext *LC = C.getLocationContext();
16870c2ee30SGeorge Karpenkov   MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
16970c2ee30SGeorge Karpenkov 
17070c2ee30SGeorge Karpenkov   for ( ; I != E; ++I) {
17170c2ee30SGeorge Karpenkov     const VarRegion *VR = I.getCapturedRegion();
17270c2ee30SGeorge Karpenkov     if (VR->getSuperRegion() == R) {
17370c2ee30SGeorge Karpenkov       VR = MemMgr.getVarRegion(VR->getDecl(), LC);
17470c2ee30SGeorge Karpenkov     }
17570c2ee30SGeorge Karpenkov     Regions.push_back(VR);
17670c2ee30SGeorge Karpenkov   }
17770c2ee30SGeorge Karpenkov 
178d3e76753SGeorge Karpenkov   state = state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
17970c2ee30SGeorge Karpenkov   C.addTransition(state);
18070c2ee30SGeorge Karpenkov }
18170c2ee30SGeorge Karpenkov 
checkPostStmt(const CastExpr * CE,CheckerContext & C) const18270c2ee30SGeorge Karpenkov void RetainCountChecker::checkPostStmt(const CastExpr *CE,
18370c2ee30SGeorge Karpenkov                                        CheckerContext &C) const {
18470c2ee30SGeorge Karpenkov   const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
18570c2ee30SGeorge Karpenkov   if (!BE)
18670c2ee30SGeorge Karpenkov     return;
18770c2ee30SGeorge Karpenkov 
188b6c6ab31SGeorge Karpenkov   QualType QT = CE->getType();
189b6c6ab31SGeorge Karpenkov   ObjKind K;
19077b35308SGeorge Karpenkov   if (QT->isObjCObjectPointerType()) {
191b6c6ab31SGeorge Karpenkov     K = ObjKind::ObjC;
19277b35308SGeorge Karpenkov   } else {
19377b35308SGeorge Karpenkov     K = ObjKind::CF;
194b6c6ab31SGeorge Karpenkov   }
195b6c6ab31SGeorge Karpenkov 
196b6c6ab31SGeorge Karpenkov   ArgEffect AE = ArgEffect(IncRef, K);
19770c2ee30SGeorge Karpenkov 
19870c2ee30SGeorge Karpenkov   switch (BE->getBridgeKind()) {
19970c2ee30SGeorge Karpenkov     case OBC_Bridge:
20070c2ee30SGeorge Karpenkov       // Do nothing.
20170c2ee30SGeorge Karpenkov       return;
20270c2ee30SGeorge Karpenkov     case OBC_BridgeRetained:
2039cbcc21aSGeorge Karpenkov       AE = AE.withKind(IncRef);
20470c2ee30SGeorge Karpenkov       break;
20570c2ee30SGeorge Karpenkov     case OBC_BridgeTransfer:
2069cbcc21aSGeorge Karpenkov       AE = AE.withKind(DecRefBridgedTransferred);
20770c2ee30SGeorge Karpenkov       break;
20870c2ee30SGeorge Karpenkov   }
20970c2ee30SGeorge Karpenkov 
21070c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
21170c2ee30SGeorge Karpenkov   SymbolRef Sym = C.getSVal(CE).getAsLocSymbol();
21270c2ee30SGeorge Karpenkov   if (!Sym)
21370c2ee30SGeorge Karpenkov     return;
21470c2ee30SGeorge Karpenkov   const RefVal* T = getRefBinding(state, Sym);
21570c2ee30SGeorge Karpenkov   if (!T)
21670c2ee30SGeorge Karpenkov     return;
21770c2ee30SGeorge Karpenkov 
21870c2ee30SGeorge Karpenkov   RefVal::Kind hasErr = (RefVal::Kind) 0;
21970c2ee30SGeorge Karpenkov   state = updateSymbol(state, Sym, *T, AE, hasErr, C);
22070c2ee30SGeorge Karpenkov 
22170c2ee30SGeorge Karpenkov   if (hasErr) {
22270c2ee30SGeorge Karpenkov     // FIXME: If we get an error during a bridge cast, should we report it?
22370c2ee30SGeorge Karpenkov     return;
22470c2ee30SGeorge Karpenkov   }
22570c2ee30SGeorge Karpenkov 
22670c2ee30SGeorge Karpenkov   C.addTransition(state);
22770c2ee30SGeorge Karpenkov }
22870c2ee30SGeorge Karpenkov 
processObjCLiterals(CheckerContext & C,const Expr * Ex) const22970c2ee30SGeorge Karpenkov void RetainCountChecker::processObjCLiterals(CheckerContext &C,
23070c2ee30SGeorge Karpenkov                                              const Expr *Ex) const {
23170c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
23270c2ee30SGeorge Karpenkov   const ExplodedNode *pred = C.getPredecessor();
23370c2ee30SGeorge Karpenkov   for (const Stmt *Child : Ex->children()) {
23470c2ee30SGeorge Karpenkov     SVal V = pred->getSVal(Child);
23570c2ee30SGeorge Karpenkov     if (SymbolRef sym = V.getAsSymbol())
23670c2ee30SGeorge Karpenkov       if (const RefVal* T = getRefBinding(state, sym)) {
23770c2ee30SGeorge Karpenkov         RefVal::Kind hasErr = (RefVal::Kind) 0;
2389cbcc21aSGeorge Karpenkov         state = updateSymbol(state, sym, *T,
2399cbcc21aSGeorge Karpenkov                              ArgEffect(MayEscape, ObjKind::ObjC), hasErr, C);
24070c2ee30SGeorge Karpenkov         if (hasErr) {
24170c2ee30SGeorge Karpenkov           processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C);
24270c2ee30SGeorge Karpenkov           return;
24370c2ee30SGeorge Karpenkov         }
24470c2ee30SGeorge Karpenkov       }
24570c2ee30SGeorge Karpenkov   }
24670c2ee30SGeorge Karpenkov 
24770c2ee30SGeorge Karpenkov   // Return the object as autoreleased.
2487e3016deSGeorge Karpenkov   //  RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC);
24970c2ee30SGeorge Karpenkov   if (SymbolRef sym =
25070c2ee30SGeorge Karpenkov         state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
25170c2ee30SGeorge Karpenkov     QualType ResultTy = Ex->getType();
25270c2ee30SGeorge Karpenkov     state = setRefBinding(state, sym,
2537e3016deSGeorge Karpenkov                           RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
25470c2ee30SGeorge Karpenkov   }
25570c2ee30SGeorge Karpenkov 
25670c2ee30SGeorge Karpenkov   C.addTransition(state);
25770c2ee30SGeorge Karpenkov }
25870c2ee30SGeorge Karpenkov 
checkPostStmt(const ObjCArrayLiteral * AL,CheckerContext & C) const25970c2ee30SGeorge Karpenkov void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
26070c2ee30SGeorge Karpenkov                                        CheckerContext &C) const {
26170c2ee30SGeorge Karpenkov   // Apply the 'MayEscape' to all values.
26270c2ee30SGeorge Karpenkov   processObjCLiterals(C, AL);
26370c2ee30SGeorge Karpenkov }
26470c2ee30SGeorge Karpenkov 
checkPostStmt(const ObjCDictionaryLiteral * DL,CheckerContext & C) const26570c2ee30SGeorge Karpenkov void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
26670c2ee30SGeorge Karpenkov                                        CheckerContext &C) const {
26770c2ee30SGeorge Karpenkov   // Apply the 'MayEscape' to all keys and values.
26870c2ee30SGeorge Karpenkov   processObjCLiterals(C, DL);
26970c2ee30SGeorge Karpenkov }
27070c2ee30SGeorge Karpenkov 
checkPostStmt(const ObjCBoxedExpr * Ex,CheckerContext & C) const27170c2ee30SGeorge Karpenkov void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
27270c2ee30SGeorge Karpenkov                                        CheckerContext &C) const {
27370c2ee30SGeorge Karpenkov   const ExplodedNode *Pred = C.getPredecessor();
27470c2ee30SGeorge Karpenkov   ProgramStateRef State = Pred->getState();
27570c2ee30SGeorge Karpenkov 
27670c2ee30SGeorge Karpenkov   if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) {
27770c2ee30SGeorge Karpenkov     QualType ResultTy = Ex->getType();
27870c2ee30SGeorge Karpenkov     State = setRefBinding(State, Sym,
2797e3016deSGeorge Karpenkov                           RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
28070c2ee30SGeorge Karpenkov   }
28170c2ee30SGeorge Karpenkov 
28270c2ee30SGeorge Karpenkov   C.addTransition(State);
28370c2ee30SGeorge Karpenkov }
28470c2ee30SGeorge Karpenkov 
checkPostStmt(const ObjCIvarRefExpr * IRE,CheckerContext & C) const28570c2ee30SGeorge Karpenkov void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
28670c2ee30SGeorge Karpenkov                                        CheckerContext &C) const {
28770c2ee30SGeorge Karpenkov   Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
28870c2ee30SGeorge Karpenkov   if (!IVarLoc)
28970c2ee30SGeorge Karpenkov     return;
29070c2ee30SGeorge Karpenkov 
29170c2ee30SGeorge Karpenkov   ProgramStateRef State = C.getState();
29270c2ee30SGeorge Karpenkov   SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
293d0ac215dSKazu Hirata   if (!Sym || !isa_and_nonnull<ObjCIvarRegion>(Sym->getOriginRegion()))
29470c2ee30SGeorge Karpenkov     return;
29570c2ee30SGeorge Karpenkov 
29670c2ee30SGeorge Karpenkov   // Accessing an ivar directly is unusual. If we've done that, be more
29770c2ee30SGeorge Karpenkov   // forgiving about what the surrounding code is allowed to do.
29870c2ee30SGeorge Karpenkov 
29970c2ee30SGeorge Karpenkov   QualType Ty = Sym->getType();
3007e3016deSGeorge Karpenkov   ObjKind Kind;
30170c2ee30SGeorge Karpenkov   if (Ty->isObjCRetainableType())
3027e3016deSGeorge Karpenkov     Kind = ObjKind::ObjC;
30370c2ee30SGeorge Karpenkov   else if (coreFoundation::isCFObjectRef(Ty))
3047e3016deSGeorge Karpenkov     Kind = ObjKind::CF;
30570c2ee30SGeorge Karpenkov   else
30670c2ee30SGeorge Karpenkov     return;
30770c2ee30SGeorge Karpenkov 
30870c2ee30SGeorge Karpenkov   // If the value is already known to be nil, don't bother tracking it.
30970c2ee30SGeorge Karpenkov   ConstraintManager &CMgr = State->getConstraintManager();
31070c2ee30SGeorge Karpenkov   if (CMgr.isNull(State, Sym).isConstrainedTrue())
31170c2ee30SGeorge Karpenkov     return;
31270c2ee30SGeorge Karpenkov 
31370c2ee30SGeorge Karpenkov   if (const RefVal *RV = getRefBinding(State, Sym)) {
31470c2ee30SGeorge Karpenkov     // If we've seen this symbol before, or we're only seeing it now because
31570c2ee30SGeorge Karpenkov     // of something the analyzer has synthesized, don't do anything.
31670c2ee30SGeorge Karpenkov     if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None ||
31770c2ee30SGeorge Karpenkov         isSynthesizedAccessor(C.getStackFrame())) {
31870c2ee30SGeorge Karpenkov       return;
31970c2ee30SGeorge Karpenkov     }
32070c2ee30SGeorge Karpenkov 
32170c2ee30SGeorge Karpenkov     // Note that this value has been loaded from an ivar.
32270c2ee30SGeorge Karpenkov     C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
32370c2ee30SGeorge Karpenkov     return;
32470c2ee30SGeorge Karpenkov   }
32570c2ee30SGeorge Karpenkov 
32670c2ee30SGeorge Karpenkov   RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty);
32770c2ee30SGeorge Karpenkov 
32870c2ee30SGeorge Karpenkov   // In a synthesized accessor, the effective retain count is +0.
32970c2ee30SGeorge Karpenkov   if (isSynthesizedAccessor(C.getStackFrame())) {
33070c2ee30SGeorge Karpenkov     C.addTransition(setRefBinding(State, Sym, PlusZero));
33170c2ee30SGeorge Karpenkov     return;
33270c2ee30SGeorge Karpenkov   }
33370c2ee30SGeorge Karpenkov 
33470c2ee30SGeorge Karpenkov   State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
33570c2ee30SGeorge Karpenkov   C.addTransition(State);
33670c2ee30SGeorge Karpenkov }
33770c2ee30SGeorge Karpenkov 
isReceiverUnconsumedSelf(const CallEvent & Call)3386fdd2bd5SGeorge Karpenkov static bool isReceiverUnconsumedSelf(const CallEvent &Call) {
3396fdd2bd5SGeorge Karpenkov   if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
3406fdd2bd5SGeorge Karpenkov 
3416fdd2bd5SGeorge Karpenkov     // Check if the message is not consumed, we know it will not be used in
3426fdd2bd5SGeorge Karpenkov     // an assignment, ex: "self = [super init]".
3436fdd2bd5SGeorge Karpenkov     return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
3446fdd2bd5SGeorge Karpenkov            !Call.getLocationContext()
3456fdd2bd5SGeorge Karpenkov                 ->getAnalysisDeclContext()
3466fdd2bd5SGeorge Karpenkov                 ->getParentMap()
3476fdd2bd5SGeorge Karpenkov                 .isConsumedExpr(Call.getOriginExpr());
3486fdd2bd5SGeorge Karpenkov   }
3496fdd2bd5SGeorge Karpenkov   return false;
3506fdd2bd5SGeorge Karpenkov }
3516fdd2bd5SGeorge Karpenkov 
getSummary(RetainSummaryManager & Summaries,const CallEvent & Call,QualType ReceiverType)3526fdd2bd5SGeorge Karpenkov const static RetainSummary *getSummary(RetainSummaryManager &Summaries,
3536fdd2bd5SGeorge Karpenkov                                        const CallEvent &Call,
3546fdd2bd5SGeorge Karpenkov                                        QualType ReceiverType) {
3556fdd2bd5SGeorge Karpenkov   const Expr *CE = Call.getOriginExpr();
3566fdd2bd5SGeorge Karpenkov   AnyCall C =
3576fdd2bd5SGeorge Karpenkov       CE ? *AnyCall::forExpr(CE)
35838bc347fSGeorge Karpenkov          : AnyCall(cast<CXXDestructorDecl>(Call.getDecl()));
3596fdd2bd5SGeorge Karpenkov   return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
3606fdd2bd5SGeorge Karpenkov                               isReceiverUnconsumedSelf(Call), ReceiverType);
3616fdd2bd5SGeorge Karpenkov }
3626fdd2bd5SGeorge Karpenkov 
checkPostCall(const CallEvent & Call,CheckerContext & C) const36370c2ee30SGeorge Karpenkov void RetainCountChecker::checkPostCall(const CallEvent &Call,
36470c2ee30SGeorge Karpenkov                                        CheckerContext &C) const {
36570c2ee30SGeorge Karpenkov   RetainSummaryManager &Summaries = getSummaryManager(C);
366efef49cdSGeorge Karpenkov 
367efef49cdSGeorge Karpenkov   // Leave null if no receiver.
368efef49cdSGeorge Karpenkov   QualType ReceiverType;
369efef49cdSGeorge Karpenkov   if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
370efef49cdSGeorge Karpenkov     if (MC->isInstanceMessage()) {
371efef49cdSGeorge Karpenkov       SVal ReceiverV = MC->getReceiverSVal();
372efef49cdSGeorge Karpenkov       if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
373efef49cdSGeorge Karpenkov         if (const RefVal *T = getRefBinding(C.getState(), Sym))
374efef49cdSGeorge Karpenkov           ReceiverType = T->getType();
375efef49cdSGeorge Karpenkov     }
376efef49cdSGeorge Karpenkov   }
377efef49cdSGeorge Karpenkov 
3786fdd2bd5SGeorge Karpenkov   const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType);
37970c2ee30SGeorge Karpenkov 
38070c2ee30SGeorge Karpenkov   if (C.wasInlined) {
38170c2ee30SGeorge Karpenkov     processSummaryOfInlined(*Summ, Call, C);
38270c2ee30SGeorge Karpenkov     return;
38370c2ee30SGeorge Karpenkov   }
38470c2ee30SGeorge Karpenkov   checkSummary(*Summ, Call, C);
38570c2ee30SGeorge Karpenkov }
38670c2ee30SGeorge Karpenkov 
38770c2ee30SGeorge Karpenkov /// GetReturnType - Used to get the return type of a message expression or
38870c2ee30SGeorge Karpenkov ///  function call with the intention of affixing that type to a tracked symbol.
38970c2ee30SGeorge Karpenkov ///  While the return type can be queried directly from RetEx, when
39070c2ee30SGeorge Karpenkov ///  invoking class methods we augment to the return type to be that of
39170c2ee30SGeorge Karpenkov ///  a pointer to the class (as opposed it just being id).
39270c2ee30SGeorge Karpenkov // FIXME: We may be able to do this with related result types instead.
39370c2ee30SGeorge Karpenkov // This function is probably overestimating.
GetReturnType(const Expr * RetE,ASTContext & Ctx)39470c2ee30SGeorge Karpenkov static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
39570c2ee30SGeorge Karpenkov   QualType RetTy = RetE->getType();
39670c2ee30SGeorge Karpenkov   // If RetE is not a message expression just return its type.
39770c2ee30SGeorge Karpenkov   // If RetE is a message expression, return its types if it is something
39870c2ee30SGeorge Karpenkov   /// more specific than id.
39970c2ee30SGeorge Karpenkov   if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
40070c2ee30SGeorge Karpenkov     if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
40170c2ee30SGeorge Karpenkov       if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
40270c2ee30SGeorge Karpenkov           PT->isObjCClassType()) {
40370c2ee30SGeorge Karpenkov         // At this point we know the return type of the message expression is
40470c2ee30SGeorge Karpenkov         // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
40570c2ee30SGeorge Karpenkov         // is a call to a class method whose type we can resolve.  In such
40670c2ee30SGeorge Karpenkov         // cases, promote the return type to XXX* (where XXX is the class).
40770c2ee30SGeorge Karpenkov         const ObjCInterfaceDecl *D = ME->getReceiverInterface();
40870c2ee30SGeorge Karpenkov         return !D ? RetTy :
40970c2ee30SGeorge Karpenkov                     Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D));
41070c2ee30SGeorge Karpenkov       }
41170c2ee30SGeorge Karpenkov 
41270c2ee30SGeorge Karpenkov   return RetTy;
41370c2ee30SGeorge Karpenkov }
41470c2ee30SGeorge Karpenkov 
refValFromRetEffect(RetEffect RE,QualType ResultTy)41580c9e78eSGeorge Karpenkov static Optional<RefVal> refValFromRetEffect(RetEffect RE,
41680c9e78eSGeorge Karpenkov                                             QualType ResultTy) {
41780c9e78eSGeorge Karpenkov   if (RE.isOwned()) {
41880c9e78eSGeorge Karpenkov     return RefVal::makeOwned(RE.getObjKind(), ResultTy);
41980c9e78eSGeorge Karpenkov   } else if (RE.notOwned()) {
42080c9e78eSGeorge Karpenkov     return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
42180c9e78eSGeorge Karpenkov   }
42280c9e78eSGeorge Karpenkov 
42380c9e78eSGeorge Karpenkov   return None;
42480c9e78eSGeorge Karpenkov }
42580c9e78eSGeorge Karpenkov 
isPointerToObject(QualType QT)426255b0582SGeorge Karpenkov static bool isPointerToObject(QualType QT) {
427255b0582SGeorge Karpenkov   QualType PT = QT->getPointeeType();
428255b0582SGeorge Karpenkov   if (!PT.isNull())
429255b0582SGeorge Karpenkov     if (PT->getAsCXXRecordDecl())
430255b0582SGeorge Karpenkov       return true;
431255b0582SGeorge Karpenkov   return false;
432255b0582SGeorge Karpenkov }
433255b0582SGeorge Karpenkov 
434255b0582SGeorge Karpenkov /// Whether the tracked value should be escaped on a given call.
435255b0582SGeorge Karpenkov /// OSObjects are escaped when passed to void * / etc.
shouldEscapeOSArgumentOnCall(const CallEvent & CE,unsigned ArgIdx,const RefVal * TrackedValue)4369cbcc21aSGeorge Karpenkov static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx,
437255b0582SGeorge Karpenkov                                        const RefVal *TrackedValue) {
4387e3016deSGeorge Karpenkov   if (TrackedValue->getObjKind() != ObjKind::OS)
439255b0582SGeorge Karpenkov     return false;
440255b0582SGeorge Karpenkov   if (ArgIdx >= CE.parameters().size())
441255b0582SGeorge Karpenkov     return false;
442255b0582SGeorge Karpenkov   return !isPointerToObject(CE.parameters()[ArgIdx]->getType());
443255b0582SGeorge Karpenkov }
444255b0582SGeorge Karpenkov 
44570c2ee30SGeorge Karpenkov // We don't always get the exact modeling of the function with regards to the
44670c2ee30SGeorge Karpenkov // retain count checker even when the function is inlined. For example, we need
44770c2ee30SGeorge Karpenkov // to stop tracking the symbols which were marked with StopTrackingHard.
processSummaryOfInlined(const RetainSummary & Summ,const CallEvent & CallOrMsg,CheckerContext & C) const44870c2ee30SGeorge Karpenkov void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
44970c2ee30SGeorge Karpenkov                                                  const CallEvent &CallOrMsg,
45070c2ee30SGeorge Karpenkov                                                  CheckerContext &C) const {
45170c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
45270c2ee30SGeorge Karpenkov 
45370c2ee30SGeorge Karpenkov   // Evaluate the effect of the arguments.
45470c2ee30SGeorge Karpenkov   for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
45570c2ee30SGeorge Karpenkov     SVal V = CallOrMsg.getArgSVal(idx);
456255b0582SGeorge Karpenkov 
45770c2ee30SGeorge Karpenkov     if (SymbolRef Sym = V.getAsLocSymbol()) {
458585a210eSGeorge Karpenkov       bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard;
459255b0582SGeorge Karpenkov       if (const RefVal *T = getRefBinding(state, Sym))
4609cbcc21aSGeorge Karpenkov         if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
461255b0582SGeorge Karpenkov           ShouldRemoveBinding = true;
462255b0582SGeorge Karpenkov 
463255b0582SGeorge Karpenkov       if (ShouldRemoveBinding)
46470c2ee30SGeorge Karpenkov         state = removeRefBinding(state, Sym);
46570c2ee30SGeorge Karpenkov     }
46670c2ee30SGeorge Karpenkov   }
46770c2ee30SGeorge Karpenkov 
46870c2ee30SGeorge Karpenkov   // Evaluate the effect on the message receiver.
4696e9fd137SGeorge Karpenkov   if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
47070c2ee30SGeorge Karpenkov     if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
471585a210eSGeorge Karpenkov       if (Summ.getReceiverEffect().getKind() == StopTrackingHard) {
47270c2ee30SGeorge Karpenkov         state = removeRefBinding(state, Sym);
47370c2ee30SGeorge Karpenkov       }
47470c2ee30SGeorge Karpenkov     }
47570c2ee30SGeorge Karpenkov   }
47670c2ee30SGeorge Karpenkov 
47770c2ee30SGeorge Karpenkov   // Consult the summary for the return value.
478ab0011ebSGeorge Karpenkov   RetEffect RE = Summ.getRetEffect();
479d5ef0d2aSGeorge Karpenkov 
480d5ef0d2aSGeorge Karpenkov   if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
481d5ef0d2aSGeorge Karpenkov     if (RE.getKind() == RetEffect::NoRetHard)
482ab0011ebSGeorge Karpenkov       state = removeRefBinding(state, Sym);
483d5ef0d2aSGeorge Karpenkov   }
48470c2ee30SGeorge Karpenkov 
48570c2ee30SGeorge Karpenkov   C.addTransition(state);
48670c2ee30SGeorge Karpenkov }
48770c2ee30SGeorge Karpenkov 
isSmartPtrField(const MemRegion * MR)4882c2d0b6eSGeorge Karpenkov static bool isSmartPtrField(const MemRegion *MR) {
4892c2d0b6eSGeorge Karpenkov   const auto *TR = dyn_cast<TypedValueRegion>(
4902c2d0b6eSGeorge Karpenkov     cast<SubRegion>(MR)->getSuperRegion());
4912c2d0b6eSGeorge Karpenkov   return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType());
4922c2d0b6eSGeorge Karpenkov }
4932c2d0b6eSGeorge Karpenkov 
4942c2d0b6eSGeorge Karpenkov 
49503391514SGeorge Karpenkov /// A value escapes in these possible cases:
49603391514SGeorge Karpenkov ///
49703391514SGeorge Karpenkov /// - binding to something that is not a memory region.
49803391514SGeorge Karpenkov /// - binding to a memregion that does not have stack storage
49903391514SGeorge Karpenkov /// - binding to a variable that has a destructor attached using CleanupAttr
50003391514SGeorge Karpenkov ///
50103391514SGeorge Karpenkov /// We do not currently model what happens when a symbol is
5022c2d0b6eSGeorge Karpenkov /// assigned to a struct field, unless it is a known smart pointer
5032c2d0b6eSGeorge Karpenkov /// implementation, about which we know that it is inlined.
50403391514SGeorge Karpenkov /// FIXME: This could definitely be improved upon.
shouldEscapeRegion(const MemRegion * R)5055be959c8SGeorge Karpenkov static bool shouldEscapeRegion(const MemRegion *R) {
5062c2d0b6eSGeorge Karpenkov   if (isSmartPtrField(R))
5072c2d0b6eSGeorge Karpenkov     return false;
5082c2d0b6eSGeorge Karpenkov 
50903391514SGeorge Karpenkov   const auto *VR = dyn_cast<VarRegion>(R);
5102c2d0b6eSGeorge Karpenkov 
51103391514SGeorge Karpenkov   if (!R->hasStackStorage() || !VR)
51203391514SGeorge Karpenkov     return true;
5135be959c8SGeorge Karpenkov 
51403391514SGeorge Karpenkov   const VarDecl *VD = VR->getDecl();
51503391514SGeorge Karpenkov   if (!VD->hasAttr<CleanupAttr>())
51603391514SGeorge Karpenkov     return false; // CleanupAttr attaches destructors, which cause escaping.
51703391514SGeorge Karpenkov   return true;
5185be959c8SGeorge Karpenkov }
5195be959c8SGeorge Karpenkov 
5205be959c8SGeorge Karpenkov static SmallVector<ProgramStateRef, 2>
updateOutParameters(ProgramStateRef State,const RetainSummary & Summ,const CallEvent & CE)5215be959c8SGeorge Karpenkov updateOutParameters(ProgramStateRef State, const RetainSummary &Summ,
5225be959c8SGeorge Karpenkov                     const CallEvent &CE) {
5235be959c8SGeorge Karpenkov 
5245be959c8SGeorge Karpenkov   SVal L = CE.getReturnValue();
5255be959c8SGeorge Karpenkov 
5265be959c8SGeorge Karpenkov   // Splitting is required to support out parameters,
5275be959c8SGeorge Karpenkov   // as out parameters might be created only on the "success" branch.
5285be959c8SGeorge Karpenkov   // We want to avoid eagerly splitting unless out parameters are actually
5295be959c8SGeorge Karpenkov   // needed.
5305be959c8SGeorge Karpenkov   bool SplitNecessary = false;
5315be959c8SGeorge Karpenkov   for (auto &P : Summ.getArgEffects())
5325be959c8SGeorge Karpenkov     if (P.second.getKind() == RetainedOutParameterOnNonZero ||
5335be959c8SGeorge Karpenkov         P.second.getKind() == RetainedOutParameterOnZero)
5345be959c8SGeorge Karpenkov       SplitNecessary = true;
5355be959c8SGeorge Karpenkov 
5365be959c8SGeorge Karpenkov   ProgramStateRef AssumeNonZeroReturn = State;
5375be959c8SGeorge Karpenkov   ProgramStateRef AssumeZeroReturn = State;
5385be959c8SGeorge Karpenkov 
5395be959c8SGeorge Karpenkov   if (SplitNecessary) {
54007c7257cSArtem Dergachev     if (!CE.getResultType()->isScalarType()) {
54107c7257cSArtem Dergachev       // Structures cannot be assumed. This probably deserves
54207c7257cSArtem Dergachev       // a compiler warning for invalid annotations.
54307c7257cSArtem Dergachev       return {State};
54407c7257cSArtem Dergachev     }
5455be959c8SGeorge Karpenkov     if (auto DL = L.getAs<DefinedOrUnknownSVal>()) {
5465be959c8SGeorge Karpenkov       AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true);
5475be959c8SGeorge Karpenkov       AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false);
5485be959c8SGeorge Karpenkov     }
5495be959c8SGeorge Karpenkov   }
5505be959c8SGeorge Karpenkov 
5515be959c8SGeorge Karpenkov   for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) {
5525be959c8SGeorge Karpenkov     SVal ArgVal = CE.getArgSVal(idx);
5535be959c8SGeorge Karpenkov     ArgEffect AE = Summ.getArg(idx);
5545be959c8SGeorge Karpenkov 
55570c2ee30SGeorge Karpenkov     auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion());
55670c2ee30SGeorge Karpenkov     if (!ArgRegion)
5575be959c8SGeorge Karpenkov       continue;
55870c2ee30SGeorge Karpenkov 
55970c2ee30SGeorge Karpenkov     QualType PointeeTy = ArgRegion->getValueType();
56070c2ee30SGeorge Karpenkov     SVal PointeeVal = State->getSVal(ArgRegion);
56170c2ee30SGeorge Karpenkov     SymbolRef Pointee = PointeeVal.getAsLocSymbol();
56270c2ee30SGeorge Karpenkov     if (!Pointee)
5635be959c8SGeorge Karpenkov       continue;
56470c2ee30SGeorge Karpenkov 
5655be959c8SGeorge Karpenkov     if (shouldEscapeRegion(ArgRegion))
5665be959c8SGeorge Karpenkov       continue;
5675be959c8SGeorge Karpenkov 
5685be959c8SGeorge Karpenkov     auto makeNotOwnedParameter = [&](ProgramStateRef St) {
5695be959c8SGeorge Karpenkov       return setRefBinding(St, Pointee,
5705be959c8SGeorge Karpenkov                            RefVal::makeNotOwned(AE.getObjKind(), PointeeTy));
5715be959c8SGeorge Karpenkov     };
5725be959c8SGeorge Karpenkov     auto makeOwnedParameter = [&](ProgramStateRef St) {
5735be959c8SGeorge Karpenkov       return setRefBinding(St, Pointee,
5745be959c8SGeorge Karpenkov                            RefVal::makeOwned(ObjKind::OS, PointeeTy));
5755be959c8SGeorge Karpenkov     };
5765be959c8SGeorge Karpenkov 
5775be959c8SGeorge Karpenkov     switch (AE.getKind()) {
57870c2ee30SGeorge Karpenkov     case UnretainedOutParameter:
5795be959c8SGeorge Karpenkov       AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
5805be959c8SGeorge Karpenkov       AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
58170c2ee30SGeorge Karpenkov       break;
58270c2ee30SGeorge Karpenkov     case RetainedOutParameter:
5835be959c8SGeorge Karpenkov       AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
5845be959c8SGeorge Karpenkov       AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
58570c2ee30SGeorge Karpenkov       break;
5865be959c8SGeorge Karpenkov     case RetainedOutParameterOnNonZero:
5875be959c8SGeorge Karpenkov       AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
5885be959c8SGeorge Karpenkov       break;
5895be959c8SGeorge Karpenkov     case RetainedOutParameterOnZero:
5905be959c8SGeorge Karpenkov       AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
5915be959c8SGeorge Karpenkov       break;
59270c2ee30SGeorge Karpenkov     default:
5935be959c8SGeorge Karpenkov       break;
5945be959c8SGeorge Karpenkov     }
59570c2ee30SGeorge Karpenkov   }
59670c2ee30SGeorge Karpenkov 
5975be959c8SGeorge Karpenkov   if (SplitNecessary) {
5985be959c8SGeorge Karpenkov     return {AssumeNonZeroReturn, AssumeZeroReturn};
5995be959c8SGeorge Karpenkov   } else {
6005be959c8SGeorge Karpenkov     assert(AssumeZeroReturn == AssumeNonZeroReturn);
6015be959c8SGeorge Karpenkov     return {AssumeZeroReturn};
6025be959c8SGeorge Karpenkov   }
60370c2ee30SGeorge Karpenkov }
60470c2ee30SGeorge Karpenkov 
checkSummary(const RetainSummary & Summ,const CallEvent & CallOrMsg,CheckerContext & C) const60570c2ee30SGeorge Karpenkov void RetainCountChecker::checkSummary(const RetainSummary &Summ,
60670c2ee30SGeorge Karpenkov                                       const CallEvent &CallOrMsg,
60770c2ee30SGeorge Karpenkov                                       CheckerContext &C) const {
60870c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
60970c2ee30SGeorge Karpenkov 
61070c2ee30SGeorge Karpenkov   // Evaluate the effect of the arguments.
61170c2ee30SGeorge Karpenkov   RefVal::Kind hasErr = (RefVal::Kind) 0;
61270c2ee30SGeorge Karpenkov   SourceRange ErrorRange;
61370c2ee30SGeorge Karpenkov   SymbolRef ErrorSym = nullptr;
61470c2ee30SGeorge Karpenkov 
615717c4c0eSGeorge Karpenkov   // Helper tag for providing diagnostics: indicate whether dealloc was sent
616717c4c0eSGeorge Karpenkov   // at this location.
617717c4c0eSGeorge Karpenkov   bool DeallocSent = false;
618717c4c0eSGeorge Karpenkov 
61970c2ee30SGeorge Karpenkov   for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
62070c2ee30SGeorge Karpenkov     SVal V = CallOrMsg.getArgSVal(idx);
62170c2ee30SGeorge Karpenkov 
6229cbcc21aSGeorge Karpenkov     ArgEffect Effect = Summ.getArg(idx);
6235be959c8SGeorge Karpenkov     if (SymbolRef Sym = V.getAsLocSymbol()) {
62470c2ee30SGeorge Karpenkov       if (const RefVal *T = getRefBinding(state, Sym)) {
625041c9fa8SGeorge Karpenkov 
6269cbcc21aSGeorge Karpenkov         if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
6279cbcc21aSGeorge Karpenkov           Effect = ArgEffect(StopTrackingHard, ObjKind::OS);
628041c9fa8SGeorge Karpenkov 
62970c2ee30SGeorge Karpenkov         state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
63070c2ee30SGeorge Karpenkov         if (hasErr) {
63170c2ee30SGeorge Karpenkov           ErrorRange = CallOrMsg.getArgSourceRange(idx);
63270c2ee30SGeorge Karpenkov           ErrorSym = Sym;
63370c2ee30SGeorge Karpenkov           break;
634717c4c0eSGeorge Karpenkov         } else if (Effect.getKind() == Dealloc) {
635717c4c0eSGeorge Karpenkov           DeallocSent = true;
63670c2ee30SGeorge Karpenkov         }
63770c2ee30SGeorge Karpenkov       }
63870c2ee30SGeorge Karpenkov     }
63970c2ee30SGeorge Karpenkov   }
64070c2ee30SGeorge Karpenkov 
641ab0011ebSGeorge Karpenkov   // Evaluate the effect on the message receiver / `this` argument.
64270c2ee30SGeorge Karpenkov   bool ReceiverIsTracked = false;
64370c2ee30SGeorge Karpenkov   if (!hasErr) {
644ab0011ebSGeorge Karpenkov     if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
64570c2ee30SGeorge Karpenkov       if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
64670c2ee30SGeorge Karpenkov         if (const RefVal *T = getRefBinding(state, Sym)) {
64770c2ee30SGeorge Karpenkov           ReceiverIsTracked = true;
648585a210eSGeorge Karpenkov           state = updateSymbol(state, Sym, *T,
6499cbcc21aSGeorge Karpenkov                                Summ.getReceiverEffect(), hasErr, C);
65070c2ee30SGeorge Karpenkov           if (hasErr) {
65170c2ee30SGeorge Karpenkov             ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
65270c2ee30SGeorge Karpenkov             ErrorSym = Sym;
653717c4c0eSGeorge Karpenkov           } else if (Summ.getReceiverEffect().getKind() == Dealloc) {
654717c4c0eSGeorge Karpenkov             DeallocSent = true;
65570c2ee30SGeorge Karpenkov           }
65670c2ee30SGeorge Karpenkov         }
65770c2ee30SGeorge Karpenkov       }
658ab0011ebSGeorge Karpenkov     } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
659ab0011ebSGeorge Karpenkov       if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
660ab0011ebSGeorge Karpenkov         if (const RefVal *T = getRefBinding(state, Sym)) {
6619cbcc21aSGeorge Karpenkov           state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
662ab0011ebSGeorge Karpenkov                                hasErr, C);
663ab0011ebSGeorge Karpenkov           if (hasErr) {
664ab0011ebSGeorge Karpenkov             ErrorRange = MCall->getOriginExpr()->getSourceRange();
665ab0011ebSGeorge Karpenkov             ErrorSym = Sym;
666ab0011ebSGeorge Karpenkov           }
667ab0011ebSGeorge Karpenkov         }
668ab0011ebSGeorge Karpenkov       }
66970c2ee30SGeorge Karpenkov     }
67070c2ee30SGeorge Karpenkov   }
67170c2ee30SGeorge Karpenkov 
67270c2ee30SGeorge Karpenkov   // Process any errors.
67370c2ee30SGeorge Karpenkov   if (hasErr) {
67470c2ee30SGeorge Karpenkov     processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
67570c2ee30SGeorge Karpenkov     return;
67670c2ee30SGeorge Karpenkov   }
67770c2ee30SGeorge Karpenkov 
67870c2ee30SGeorge Karpenkov   // Consult the summary for the return value.
67970c2ee30SGeorge Karpenkov   RetEffect RE = Summ.getRetEffect();
68070c2ee30SGeorge Karpenkov 
68170c2ee30SGeorge Karpenkov   if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
68270c2ee30SGeorge Karpenkov     if (ReceiverIsTracked)
68370c2ee30SGeorge Karpenkov       RE = getSummaryManager(C).getObjAllocRetEffect();
68470c2ee30SGeorge Karpenkov     else
68570c2ee30SGeorge Karpenkov       RE = RetEffect::MakeNoRet();
68670c2ee30SGeorge Karpenkov   }
68770c2ee30SGeorge Karpenkov 
68880c9e78eSGeorge Karpenkov   if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
68970c2ee30SGeorge Karpenkov     QualType ResultTy = CallOrMsg.getResultType();
69080c9e78eSGeorge Karpenkov     if (RE.notOwned()) {
69170c2ee30SGeorge Karpenkov       const Expr *Ex = CallOrMsg.getOriginExpr();
69270c2ee30SGeorge Karpenkov       assert(Ex);
69380c9e78eSGeorge Karpenkov       ResultTy = GetReturnType(Ex, C.getASTContext());
69470c2ee30SGeorge Karpenkov     }
69580c9e78eSGeorge Karpenkov     if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
69680c9e78eSGeorge Karpenkov       state = setRefBinding(state, Sym, *updatedRefVal);
69770c2ee30SGeorge Karpenkov   }
69870c2ee30SGeorge Karpenkov 
6995be959c8SGeorge Karpenkov   SmallVector<ProgramStateRef, 2> Out =
7005be959c8SGeorge Karpenkov       updateOutParameters(state, Summ, CallOrMsg);
7015be959c8SGeorge Karpenkov 
7025be959c8SGeorge Karpenkov   for (ProgramStateRef St : Out) {
703717c4c0eSGeorge Karpenkov     if (DeallocSent) {
7045192783bSKirstóf Umann       C.addTransition(St, C.getPredecessor(), &getDeallocSentTag());
70570c2ee30SGeorge Karpenkov     } else {
7065be959c8SGeorge Karpenkov       C.addTransition(St);
7075be959c8SGeorge Karpenkov     }
70870c2ee30SGeorge Karpenkov   }
70970c2ee30SGeorge Karpenkov }
71070c2ee30SGeorge Karpenkov 
updateSymbol(ProgramStateRef state,SymbolRef sym,RefVal V,ArgEffect AE,RefVal::Kind & hasErr,CheckerContext & C) const711585a210eSGeorge Karpenkov ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
712585a210eSGeorge Karpenkov                                                  SymbolRef sym, RefVal V,
7139cbcc21aSGeorge Karpenkov                                                  ArgEffect AE,
714585a210eSGeorge Karpenkov                                                  RefVal::Kind &hasErr,
71570c2ee30SGeorge Karpenkov                                                  CheckerContext &C) const {
71670c2ee30SGeorge Karpenkov   bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
7179cbcc21aSGeorge Karpenkov   if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) {
7189cbcc21aSGeorge Karpenkov     switch (AE.getKind()) {
71970c2ee30SGeorge Karpenkov     default:
72070c2ee30SGeorge Karpenkov       break;
7219cbcc21aSGeorge Karpenkov     case IncRef:
7229cbcc21aSGeorge Karpenkov       AE = AE.withKind(DoNothing);
72370c2ee30SGeorge Karpenkov       break;
7249cbcc21aSGeorge Karpenkov     case DecRef:
7259cbcc21aSGeorge Karpenkov       AE = AE.withKind(DoNothing);
72670c2ee30SGeorge Karpenkov       break;
7279cbcc21aSGeorge Karpenkov     case DecRefAndStopTrackingHard:
7289cbcc21aSGeorge Karpenkov       AE = AE.withKind(StopTracking);
72970c2ee30SGeorge Karpenkov       break;
73070c2ee30SGeorge Karpenkov     }
7319cbcc21aSGeorge Karpenkov   }
73270c2ee30SGeorge Karpenkov 
73370c2ee30SGeorge Karpenkov   // Handle all use-after-releases.
73470c2ee30SGeorge Karpenkov   if (V.getKind() == RefVal::Released) {
73570c2ee30SGeorge Karpenkov     V = V ^ RefVal::ErrorUseAfterRelease;
73670c2ee30SGeorge Karpenkov     hasErr = V.getKind();
73770c2ee30SGeorge Karpenkov     return setRefBinding(state, sym, V);
73870c2ee30SGeorge Karpenkov   }
73970c2ee30SGeorge Karpenkov 
7409cbcc21aSGeorge Karpenkov   switch (AE.getKind()) {
74170c2ee30SGeorge Karpenkov     case UnretainedOutParameter:
74270c2ee30SGeorge Karpenkov     case RetainedOutParameter:
7435be959c8SGeorge Karpenkov     case RetainedOutParameterOnZero:
7445be959c8SGeorge Karpenkov     case RetainedOutParameterOnNonZero:
74570c2ee30SGeorge Karpenkov       llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
74670c2ee30SGeorge Karpenkov                        "not have ref state.");
74770c2ee30SGeorge Karpenkov 
748717c4c0eSGeorge Karpenkov     case Dealloc: // NB. we only need to add a note in a non-error case.
74970c2ee30SGeorge Karpenkov       switch (V.getKind()) {
75070c2ee30SGeorge Karpenkov         default:
75170c2ee30SGeorge Karpenkov           llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
75270c2ee30SGeorge Karpenkov         case RefVal::Owned:
75370c2ee30SGeorge Karpenkov           // The object immediately transitions to the released state.
75470c2ee30SGeorge Karpenkov           V = V ^ RefVal::Released;
75570c2ee30SGeorge Karpenkov           V.clearCounts();
75670c2ee30SGeorge Karpenkov           return setRefBinding(state, sym, V);
75770c2ee30SGeorge Karpenkov         case RefVal::NotOwned:
75870c2ee30SGeorge Karpenkov           V = V ^ RefVal::ErrorDeallocNotOwned;
75970c2ee30SGeorge Karpenkov           hasErr = V.getKind();
76070c2ee30SGeorge Karpenkov           break;
76170c2ee30SGeorge Karpenkov       }
76270c2ee30SGeorge Karpenkov       break;
76370c2ee30SGeorge Karpenkov 
76470c2ee30SGeorge Karpenkov     case MayEscape:
76570c2ee30SGeorge Karpenkov       if (V.getKind() == RefVal::Owned) {
76670c2ee30SGeorge Karpenkov         V = V ^ RefVal::NotOwned;
76770c2ee30SGeorge Karpenkov         break;
76870c2ee30SGeorge Karpenkov       }
76970c2ee30SGeorge Karpenkov 
7704dc0b1acSReid Kleckner       LLVM_FALLTHROUGH;
77170c2ee30SGeorge Karpenkov 
77270c2ee30SGeorge Karpenkov     case DoNothing:
77370c2ee30SGeorge Karpenkov       return state;
77470c2ee30SGeorge Karpenkov 
77570c2ee30SGeorge Karpenkov     case Autorelease:
77670c2ee30SGeorge Karpenkov       // Update the autorelease counts.
77770c2ee30SGeorge Karpenkov       V = V.autorelease();
77870c2ee30SGeorge Karpenkov       break;
77970c2ee30SGeorge Karpenkov 
78070c2ee30SGeorge Karpenkov     case StopTracking:
78170c2ee30SGeorge Karpenkov     case StopTrackingHard:
78270c2ee30SGeorge Karpenkov       return removeRefBinding(state, sym);
78370c2ee30SGeorge Karpenkov 
78470c2ee30SGeorge Karpenkov     case IncRef:
78570c2ee30SGeorge Karpenkov       switch (V.getKind()) {
78670c2ee30SGeorge Karpenkov         default:
78770c2ee30SGeorge Karpenkov           llvm_unreachable("Invalid RefVal state for a retain.");
78870c2ee30SGeorge Karpenkov         case RefVal::Owned:
78970c2ee30SGeorge Karpenkov         case RefVal::NotOwned:
79070c2ee30SGeorge Karpenkov           V = V + 1;
79170c2ee30SGeorge Karpenkov           break;
79270c2ee30SGeorge Karpenkov       }
79370c2ee30SGeorge Karpenkov       break;
79470c2ee30SGeorge Karpenkov 
79570c2ee30SGeorge Karpenkov     case DecRef:
79670c2ee30SGeorge Karpenkov     case DecRefBridgedTransferred:
79770c2ee30SGeorge Karpenkov     case DecRefAndStopTrackingHard:
79870c2ee30SGeorge Karpenkov       switch (V.getKind()) {
79970c2ee30SGeorge Karpenkov         default:
80070c2ee30SGeorge Karpenkov           // case 'RefVal::Released' handled above.
80170c2ee30SGeorge Karpenkov           llvm_unreachable("Invalid RefVal state for a release.");
80270c2ee30SGeorge Karpenkov 
80370c2ee30SGeorge Karpenkov         case RefVal::Owned:
80470c2ee30SGeorge Karpenkov           assert(V.getCount() > 0);
80570c2ee30SGeorge Karpenkov           if (V.getCount() == 1) {
8069cbcc21aSGeorge Karpenkov             if (AE.getKind() == DecRefBridgedTransferred ||
80770c2ee30SGeorge Karpenkov                 V.getIvarAccessHistory() ==
80870c2ee30SGeorge Karpenkov                   RefVal::IvarAccessHistory::AccessedDirectly)
80970c2ee30SGeorge Karpenkov               V = V ^ RefVal::NotOwned;
81070c2ee30SGeorge Karpenkov             else
81170c2ee30SGeorge Karpenkov               V = V ^ RefVal::Released;
8129cbcc21aSGeorge Karpenkov           } else if (AE.getKind() == DecRefAndStopTrackingHard) {
81370c2ee30SGeorge Karpenkov             return removeRefBinding(state, sym);
81470c2ee30SGeorge Karpenkov           }
81570c2ee30SGeorge Karpenkov 
81670c2ee30SGeorge Karpenkov           V = V - 1;
81770c2ee30SGeorge Karpenkov           break;
81870c2ee30SGeorge Karpenkov 
81970c2ee30SGeorge Karpenkov         case RefVal::NotOwned:
82070c2ee30SGeorge Karpenkov           if (V.getCount() > 0) {
8219cbcc21aSGeorge Karpenkov             if (AE.getKind() == DecRefAndStopTrackingHard)
82270c2ee30SGeorge Karpenkov               return removeRefBinding(state, sym);
82370c2ee30SGeorge Karpenkov             V = V - 1;
82470c2ee30SGeorge Karpenkov           } else if (V.getIvarAccessHistory() ==
82570c2ee30SGeorge Karpenkov                        RefVal::IvarAccessHistory::AccessedDirectly) {
82670c2ee30SGeorge Karpenkov             // Assume that the instance variable was holding on the object at
82770c2ee30SGeorge Karpenkov             // +1, and we just didn't know.
8289cbcc21aSGeorge Karpenkov             if (AE.getKind() == DecRefAndStopTrackingHard)
82970c2ee30SGeorge Karpenkov               return removeRefBinding(state, sym);
83070c2ee30SGeorge Karpenkov             V = V.releaseViaIvar() ^ RefVal::Released;
83170c2ee30SGeorge Karpenkov           } else {
83270c2ee30SGeorge Karpenkov             V = V ^ RefVal::ErrorReleaseNotOwned;
83370c2ee30SGeorge Karpenkov             hasErr = V.getKind();
83470c2ee30SGeorge Karpenkov           }
83570c2ee30SGeorge Karpenkov           break;
83670c2ee30SGeorge Karpenkov       }
83770c2ee30SGeorge Karpenkov       break;
83870c2ee30SGeorge Karpenkov   }
83970c2ee30SGeorge Karpenkov   return setRefBinding(state, sym, V);
84070c2ee30SGeorge Karpenkov }
84170c2ee30SGeorge Karpenkov 
8422c2d0b6eSGeorge Karpenkov const RefCountBug &
errorKindToBugKind(RefVal::Kind ErrorKind,SymbolRef Sym) const8432c2d0b6eSGeorge Karpenkov RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
8442c2d0b6eSGeorge Karpenkov                                        SymbolRef Sym) const {
8452c2d0b6eSGeorge Karpenkov   switch (ErrorKind) {
8462c2d0b6eSGeorge Karpenkov     case RefVal::ErrorUseAfterRelease:
8475192783bSKirstóf Umann       return *UseAfterRelease;
8482c2d0b6eSGeorge Karpenkov     case RefVal::ErrorReleaseNotOwned:
8495192783bSKirstóf Umann       return *ReleaseNotOwned;
8502c2d0b6eSGeorge Karpenkov     case RefVal::ErrorDeallocNotOwned:
8512c2d0b6eSGeorge Karpenkov       if (Sym->getType()->getPointeeCXXRecordDecl())
8525192783bSKirstóf Umann         return *FreeNotOwned;
8535192783bSKirstóf Umann       return *DeallocNotOwned;
8542c2d0b6eSGeorge Karpenkov     default:
8552c2d0b6eSGeorge Karpenkov       llvm_unreachable("Unhandled error.");
8562c2d0b6eSGeorge Karpenkov   }
8572c2d0b6eSGeorge Karpenkov }
8582c2d0b6eSGeorge Karpenkov 
processNonLeakError(ProgramStateRef St,SourceRange ErrorRange,RefVal::Kind ErrorKind,SymbolRef Sym,CheckerContext & C) const85970c2ee30SGeorge Karpenkov void RetainCountChecker::processNonLeakError(ProgramStateRef St,
86070c2ee30SGeorge Karpenkov                                              SourceRange ErrorRange,
86170c2ee30SGeorge Karpenkov                                              RefVal::Kind ErrorKind,
86270c2ee30SGeorge Karpenkov                                              SymbolRef Sym,
86370c2ee30SGeorge Karpenkov                                              CheckerContext &C) const {
86470c2ee30SGeorge Karpenkov   // HACK: Ignore retain-count issues on values accessed through ivars,
86570c2ee30SGeorge Karpenkov   // because of cases like this:
86670c2ee30SGeorge Karpenkov   //   [_contentView retain];
86770c2ee30SGeorge Karpenkov   //   [_contentView removeFromSuperview];
86870c2ee30SGeorge Karpenkov   //   [self addSubview:_contentView]; // invalidates 'self'
86970c2ee30SGeorge Karpenkov   //   [_contentView release];
87070c2ee30SGeorge Karpenkov   if (const RefVal *RV = getRefBinding(St, Sym))
87170c2ee30SGeorge Karpenkov     if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
87270c2ee30SGeorge Karpenkov       return;
87370c2ee30SGeorge Karpenkov 
87470c2ee30SGeorge Karpenkov   ExplodedNode *N = C.generateErrorNode(St);
87570c2ee30SGeorge Karpenkov   if (!N)
87670c2ee30SGeorge Karpenkov     return;
87770c2ee30SGeorge Karpenkov 
8782b3d49b6SJonas Devlieghere   auto report = std::make_unique<RefCountReport>(
8792c2d0b6eSGeorge Karpenkov       errorKindToBugKind(ErrorKind, Sym),
8802c2d0b6eSGeorge Karpenkov       C.getASTContext().getLangOpts(), N, Sym);
88170c2ee30SGeorge Karpenkov   report->addRange(ErrorRange);
88270c2ee30SGeorge Karpenkov   C.emitReport(std::move(report));
88370c2ee30SGeorge Karpenkov }
88470c2ee30SGeorge Karpenkov 
88570c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
88670c2ee30SGeorge Karpenkov // Handle the return values of retain-count-related functions.
88770c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
88870c2ee30SGeorge Karpenkov 
evalCall(const CallEvent & Call,CheckerContext & C) const88944820630SArtem Dergachev bool RetainCountChecker::evalCall(const CallEvent &Call,
89044820630SArtem Dergachev                                   CheckerContext &C) const {
89170c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
89244820630SArtem Dergachev   const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
89370c2ee30SGeorge Karpenkov   if (!FD)
89470c2ee30SGeorge Karpenkov     return false;
89570c2ee30SGeorge Karpenkov 
89644820630SArtem Dergachev   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
89744820630SArtem Dergachev   if (!CE)
89844820630SArtem Dergachev     return false;
89944820630SArtem Dergachev 
900c4d6b93dSGeorge Karpenkov   RetainSummaryManager &SmrMgr = getSummaryManager(C);
90144820630SArtem Dergachev   QualType ResultTy = Call.getResultType();
90270c2ee30SGeorge Karpenkov 
90370c2ee30SGeorge Karpenkov   // See if the function has 'rc_ownership_trusted_implementation'
90470c2ee30SGeorge Karpenkov   // annotate attribute. If it does, we will not inline it.
90570c2ee30SGeorge Karpenkov   bool hasTrustedImplementationAnnotation = false;
90670c2ee30SGeorge Karpenkov 
90741dc8de6SGeorge Karpenkov   const LocationContext *LCtx = C.getLocationContext();
90841dc8de6SGeorge Karpenkov 
9093c2ed8f3SGeorge Karpenkov   using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
9103c2ed8f3SGeorge Karpenkov   Optional<BehaviorSummary> BSmr =
9113c2ed8f3SGeorge Karpenkov       SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
9123c2ed8f3SGeorge Karpenkov 
913c4d6b93dSGeorge Karpenkov   // See if it's one of the specific functions we know how to eval.
9143c2ed8f3SGeorge Karpenkov   if (!BSmr)
91570c2ee30SGeorge Karpenkov     return false;
91670c2ee30SGeorge Karpenkov 
91770c2ee30SGeorge Karpenkov   // Bind the return value.
9183c2ed8f3SGeorge Karpenkov   if (BSmr == BehaviorSummary::Identity ||
919db0c66eeSGeorge Karpenkov       BSmr == BehaviorSummary::IdentityOrZero ||
920db0c66eeSGeorge Karpenkov       BSmr == BehaviorSummary::IdentityThis) {
921db0c66eeSGeorge Karpenkov 
922db0c66eeSGeorge Karpenkov     const Expr *BindReturnTo =
923db0c66eeSGeorge Karpenkov         (BSmr == BehaviorSummary::IdentityThis)
924db0c66eeSGeorge Karpenkov             ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
925db0c66eeSGeorge Karpenkov             : CE->getArg(0);
926db0c66eeSGeorge Karpenkov     SVal RetVal = state->getSVal(BindReturnTo, LCtx);
92748de582fSGeorge Karpenkov 
92870c2ee30SGeorge Karpenkov     // If the receiver is unknown or the function has
92970c2ee30SGeorge Karpenkov     // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
93070c2ee30SGeorge Karpenkov     // return value.
931db0c66eeSGeorge Karpenkov     // FIXME: this branch is very strange.
93248de582fSGeorge Karpenkov     if (RetVal.isUnknown() ||
93348de582fSGeorge Karpenkov         (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
93470c2ee30SGeorge Karpenkov       SValBuilder &SVB = C.getSValBuilder();
93548de582fSGeorge Karpenkov       RetVal =
93648de582fSGeorge Karpenkov           SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
93770c2ee30SGeorge Karpenkov     }
938db0c66eeSGeorge Karpenkov 
939db0c66eeSGeorge Karpenkov     // Bind the value.
9403c2ed8f3SGeorge Karpenkov     state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
9413c2ed8f3SGeorge Karpenkov 
9423c2ed8f3SGeorge Karpenkov     if (BSmr == BehaviorSummary::IdentityOrZero) {
9433c2ed8f3SGeorge Karpenkov       // Add a branch where the output is zero.
9443c2ed8f3SGeorge Karpenkov       ProgramStateRef NullOutputState = C.getState();
9453c2ed8f3SGeorge Karpenkov 
9463c2ed8f3SGeorge Karpenkov       // Assume that output is zero on the other branch.
9473c2ed8f3SGeorge Karpenkov       NullOutputState = NullOutputState->BindExpr(
94898588841SVince Bridgers           CE, LCtx, C.getSValBuilder().makeNullWithType(ResultTy),
94998588841SVince Bridgers           /*Invalidate=*/false);
9505192783bSKirstóf Umann       C.addTransition(NullOutputState, &getCastFailTag());
9513c2ed8f3SGeorge Karpenkov 
9523c2ed8f3SGeorge Karpenkov       // And on the original branch assume that both input and
9533c2ed8f3SGeorge Karpenkov       // output are non-zero.
9543c2ed8f3SGeorge Karpenkov       if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
95549a3ad21SRui Ueyama         state = state->assume(*L, /*assumption=*/true);
9563c2ed8f3SGeorge Karpenkov 
9573c2ed8f3SGeorge Karpenkov     }
95848de582fSGeorge Karpenkov   }
95970c2ee30SGeorge Karpenkov 
96070c2ee30SGeorge Karpenkov   C.addTransition(state);
96170c2ee30SGeorge Karpenkov   return true;
96270c2ee30SGeorge Karpenkov }
96370c2ee30SGeorge Karpenkov 
processReturn(const ReturnStmt * S,CheckerContext & C) const96404553e53SGeorge Karpenkov ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
96570c2ee30SGeorge Karpenkov                                                  CheckerContext &C) const {
96604553e53SGeorge Karpenkov   ExplodedNode *Pred = C.getPredecessor();
96770c2ee30SGeorge Karpenkov 
96870c2ee30SGeorge Karpenkov   // Only adjust the reference count if this is the top-level call frame,
96970c2ee30SGeorge Karpenkov   // and not the result of inlining.  In the future, we should do
97070c2ee30SGeorge Karpenkov   // better checking even for inlined calls, and see if they match
97170c2ee30SGeorge Karpenkov   // with their expected semantics (e.g., the method should return a retained
97270c2ee30SGeorge Karpenkov   // object, etc.).
97370c2ee30SGeorge Karpenkov   if (!C.inTopFrame())
97404553e53SGeorge Karpenkov     return Pred;
97504553e53SGeorge Karpenkov 
97604553e53SGeorge Karpenkov   if (!S)
97704553e53SGeorge Karpenkov     return Pred;
97870c2ee30SGeorge Karpenkov 
97970c2ee30SGeorge Karpenkov   const Expr *RetE = S->getRetValue();
98070c2ee30SGeorge Karpenkov   if (!RetE)
98104553e53SGeorge Karpenkov     return Pred;
98270c2ee30SGeorge Karpenkov 
98370c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
984e264ac6aSArtem Dergachev   // We need to dig down to the symbolic base here because various
985e264ac6aSArtem Dergachev   // custom allocators do sometimes return the symbol with an offset.
986e264ac6aSArtem Dergachev   SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext())
987e264ac6aSArtem Dergachev                       .getAsLocSymbol(/*IncludeBaseRegions=*/true);
98870c2ee30SGeorge Karpenkov   if (!Sym)
98904553e53SGeorge Karpenkov     return Pred;
99070c2ee30SGeorge Karpenkov 
99170c2ee30SGeorge Karpenkov   // Get the reference count binding (if any).
99270c2ee30SGeorge Karpenkov   const RefVal *T = getRefBinding(state, Sym);
99370c2ee30SGeorge Karpenkov   if (!T)
99404553e53SGeorge Karpenkov     return Pred;
99570c2ee30SGeorge Karpenkov 
99670c2ee30SGeorge Karpenkov   // Change the reference count.
99770c2ee30SGeorge Karpenkov   RefVal X = *T;
99870c2ee30SGeorge Karpenkov 
99970c2ee30SGeorge Karpenkov   switch (X.getKind()) {
100070c2ee30SGeorge Karpenkov     case RefVal::Owned: {
100170c2ee30SGeorge Karpenkov       unsigned cnt = X.getCount();
100270c2ee30SGeorge Karpenkov       assert(cnt > 0);
100370c2ee30SGeorge Karpenkov       X.setCount(cnt - 1);
100470c2ee30SGeorge Karpenkov       X = X ^ RefVal::ReturnedOwned;
100570c2ee30SGeorge Karpenkov       break;
100670c2ee30SGeorge Karpenkov     }
100770c2ee30SGeorge Karpenkov 
100870c2ee30SGeorge Karpenkov     case RefVal::NotOwned: {
100970c2ee30SGeorge Karpenkov       unsigned cnt = X.getCount();
101070c2ee30SGeorge Karpenkov       if (cnt) {
101170c2ee30SGeorge Karpenkov         X.setCount(cnt - 1);
101270c2ee30SGeorge Karpenkov         X = X ^ RefVal::ReturnedOwned;
101304553e53SGeorge Karpenkov       } else {
101470c2ee30SGeorge Karpenkov         X = X ^ RefVal::ReturnedNotOwned;
101570c2ee30SGeorge Karpenkov       }
101670c2ee30SGeorge Karpenkov       break;
101770c2ee30SGeorge Karpenkov     }
101870c2ee30SGeorge Karpenkov 
101970c2ee30SGeorge Karpenkov     default:
102004553e53SGeorge Karpenkov       return Pred;
102170c2ee30SGeorge Karpenkov   }
102270c2ee30SGeorge Karpenkov 
102370c2ee30SGeorge Karpenkov   // Update the binding.
102470c2ee30SGeorge Karpenkov   state = setRefBinding(state, Sym, X);
102504553e53SGeorge Karpenkov   Pred = C.addTransition(state);
102670c2ee30SGeorge Karpenkov 
102770c2ee30SGeorge Karpenkov   // At this point we have updated the state properly.
102870c2ee30SGeorge Karpenkov   // Everything after this is merely checking to see if the return value has
102970c2ee30SGeorge Karpenkov   // been over- or under-retained.
103070c2ee30SGeorge Karpenkov 
103170c2ee30SGeorge Karpenkov   // Did we cache out?
103270c2ee30SGeorge Karpenkov   if (!Pred)
103304553e53SGeorge Karpenkov     return nullptr;
103470c2ee30SGeorge Karpenkov 
103570c2ee30SGeorge Karpenkov   // Update the autorelease counts.
103670c2ee30SGeorge Karpenkov   static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease");
103704553e53SGeorge Karpenkov   state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S);
103870c2ee30SGeorge Karpenkov 
103904553e53SGeorge Karpenkov   // Have we generated a sink node?
104070c2ee30SGeorge Karpenkov   if (!state)
104104553e53SGeorge Karpenkov     return nullptr;
104270c2ee30SGeorge Karpenkov 
104370c2ee30SGeorge Karpenkov   // Get the updated binding.
104470c2ee30SGeorge Karpenkov   T = getRefBinding(state, Sym);
104570c2ee30SGeorge Karpenkov   assert(T);
104670c2ee30SGeorge Karpenkov   X = *T;
104770c2ee30SGeorge Karpenkov 
104870c2ee30SGeorge Karpenkov   // Consult the summary of the enclosing method.
104970c2ee30SGeorge Karpenkov   RetainSummaryManager &Summaries = getSummaryManager(C);
105070c2ee30SGeorge Karpenkov   const Decl *CD = &Pred->getCodeDecl();
105170c2ee30SGeorge Karpenkov   RetEffect RE = RetEffect::MakeNoRet();
105270c2ee30SGeorge Karpenkov 
105370c2ee30SGeorge Karpenkov   // FIXME: What is the convention for blocks? Is there one?
105470c2ee30SGeorge Karpenkov   if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
10552e466678SGeorge Karpenkov     const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD));
105670c2ee30SGeorge Karpenkov     RE = Summ->getRetEffect();
105770c2ee30SGeorge Karpenkov   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
105870c2ee30SGeorge Karpenkov     if (!isa<CXXMethodDecl>(FD)) {
10592e466678SGeorge Karpenkov       const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD));
106070c2ee30SGeorge Karpenkov       RE = Summ->getRetEffect();
106170c2ee30SGeorge Karpenkov     }
106270c2ee30SGeorge Karpenkov   }
106370c2ee30SGeorge Karpenkov 
106404553e53SGeorge Karpenkov   return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
106570c2ee30SGeorge Karpenkov }
106670c2ee30SGeorge Karpenkov 
checkReturnWithRetEffect(const ReturnStmt * S,CheckerContext & C,ExplodedNode * Pred,RetEffect RE,RefVal X,SymbolRef Sym,ProgramStateRef state) const106704553e53SGeorge Karpenkov ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
106870c2ee30SGeorge Karpenkov                                                   CheckerContext &C,
106970c2ee30SGeorge Karpenkov                                                   ExplodedNode *Pred,
107070c2ee30SGeorge Karpenkov                                                   RetEffect RE, RefVal X,
107170c2ee30SGeorge Karpenkov                                                   SymbolRef Sym,
107270c2ee30SGeorge Karpenkov                                                   ProgramStateRef state) const {
107370c2ee30SGeorge Karpenkov   // HACK: Ignore retain-count issues on values accessed through ivars,
107470c2ee30SGeorge Karpenkov   // because of cases like this:
107570c2ee30SGeorge Karpenkov   //   [_contentView retain];
107670c2ee30SGeorge Karpenkov   //   [_contentView removeFromSuperview];
107770c2ee30SGeorge Karpenkov   //   [self addSubview:_contentView]; // invalidates 'self'
107870c2ee30SGeorge Karpenkov   //   [_contentView release];
107970c2ee30SGeorge Karpenkov   if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
108004553e53SGeorge Karpenkov     return Pred;
108170c2ee30SGeorge Karpenkov 
108270c2ee30SGeorge Karpenkov   // Any leaks or other errors?
108370c2ee30SGeorge Karpenkov   if (X.isReturnedOwned() && X.getCount() == 0) {
108470c2ee30SGeorge Karpenkov     if (RE.getKind() != RetEffect::NoRet) {
108570c2ee30SGeorge Karpenkov       if (!RE.isOwned()) {
108604553e53SGeorge Karpenkov 
108770c2ee30SGeorge Karpenkov         // The returning type is a CF, we expect the enclosing method should
108870c2ee30SGeorge Karpenkov         // return ownership.
108970c2ee30SGeorge Karpenkov         X = X ^ RefVal::ErrorLeakReturned;
109070c2ee30SGeorge Karpenkov 
109170c2ee30SGeorge Karpenkov         // Generate an error node.
109270c2ee30SGeorge Karpenkov         state = setRefBinding(state, Sym, X);
109370c2ee30SGeorge Karpenkov 
109470c2ee30SGeorge Karpenkov         static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak");
109570c2ee30SGeorge Karpenkov         ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
109670c2ee30SGeorge Karpenkov         if (N) {
109770c2ee30SGeorge Karpenkov           const LangOptions &LOpts = C.getASTContext().getLangOpts();
10982c2d0b6eSGeorge Karpenkov           auto R =
10995192783bSKirstóf Umann               std::make_unique<RefLeakReport>(*LeakAtReturn, LOpts, N, Sym, C);
110004553e53SGeorge Karpenkov           C.emitReport(std::move(R));
110170c2ee30SGeorge Karpenkov         }
110204553e53SGeorge Karpenkov         return N;
110370c2ee30SGeorge Karpenkov       }
110470c2ee30SGeorge Karpenkov     }
110570c2ee30SGeorge Karpenkov   } else if (X.isReturnedNotOwned()) {
110670c2ee30SGeorge Karpenkov     if (RE.isOwned()) {
110770c2ee30SGeorge Karpenkov       if (X.getIvarAccessHistory() ==
110870c2ee30SGeorge Karpenkov             RefVal::IvarAccessHistory::AccessedDirectly) {
110970c2ee30SGeorge Karpenkov         // Assume the method was trying to transfer a +1 reference from a
111070c2ee30SGeorge Karpenkov         // strong ivar to the caller.
111170c2ee30SGeorge Karpenkov         state = setRefBinding(state, Sym,
111270c2ee30SGeorge Karpenkov                               X.releaseViaIvar() ^ RefVal::ReturnedOwned);
111370c2ee30SGeorge Karpenkov       } else {
111470c2ee30SGeorge Karpenkov         // Trying to return a not owned object to a caller expecting an
111570c2ee30SGeorge Karpenkov         // owned object.
111670c2ee30SGeorge Karpenkov         state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
111770c2ee30SGeorge Karpenkov 
111870c2ee30SGeorge Karpenkov         static CheckerProgramPointTag
111970c2ee30SGeorge Karpenkov             ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned");
112070c2ee30SGeorge Karpenkov 
112170c2ee30SGeorge Karpenkov         ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
112270c2ee30SGeorge Karpenkov         if (N) {
11232b3d49b6SJonas Devlieghere           auto R = std::make_unique<RefCountReport>(
11245192783bSKirstóf Umann               *ReturnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
112504553e53SGeorge Karpenkov           C.emitReport(std::move(R));
112604553e53SGeorge Karpenkov         }
112704553e53SGeorge Karpenkov         return N;
112870c2ee30SGeorge Karpenkov       }
112970c2ee30SGeorge Karpenkov     }
113070c2ee30SGeorge Karpenkov   }
113104553e53SGeorge Karpenkov   return Pred;
113270c2ee30SGeorge Karpenkov }
113370c2ee30SGeorge Karpenkov 
113470c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
113570c2ee30SGeorge Karpenkov // Check various ways a symbol can be invalidated.
113670c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
113770c2ee30SGeorge Karpenkov 
checkBind(SVal loc,SVal val,const Stmt * S,CheckerContext & C) const113870c2ee30SGeorge Karpenkov void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
113970c2ee30SGeorge Karpenkov                                    CheckerContext &C) const {
114070c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
114103391514SGeorge Karpenkov   const MemRegion *MR = loc.getAsRegion();
114270c2ee30SGeorge Karpenkov 
114303391514SGeorge Karpenkov   // Find all symbols referenced by 'val' that we are tracking
114470c2ee30SGeorge Karpenkov   // and stop tracking them.
114503391514SGeorge Karpenkov   if (MR && shouldEscapeRegion(MR)) {
114670c2ee30SGeorge Karpenkov     state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
114770c2ee30SGeorge Karpenkov     C.addTransition(state);
114870c2ee30SGeorge Karpenkov   }
114903391514SGeorge Karpenkov }
115070c2ee30SGeorge Karpenkov 
evalAssume(ProgramStateRef state,SVal Cond,bool Assumption) const115170c2ee30SGeorge Karpenkov ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
115270c2ee30SGeorge Karpenkov                                                SVal Cond,
115370c2ee30SGeorge Karpenkov                                                bool Assumption) const {
115470c2ee30SGeorge Karpenkov   // FIXME: We may add to the interface of evalAssume the list of symbols
115570c2ee30SGeorge Karpenkov   //  whose assumptions have changed.  For now we just iterate through the
115670c2ee30SGeorge Karpenkov   //  bindings and check if any of the tracked symbols are NULL.  This isn't
115770c2ee30SGeorge Karpenkov   //  too bad since the number of symbols we will track in practice are
115870c2ee30SGeorge Karpenkov   //  probably small and evalAssume is only called at branches and a few
115970c2ee30SGeorge Karpenkov   //  other places.
116070c2ee30SGeorge Karpenkov   RefBindingsTy B = state->get<RefBindings>();
116170c2ee30SGeorge Karpenkov 
116270c2ee30SGeorge Karpenkov   if (B.isEmpty())
116370c2ee30SGeorge Karpenkov     return state;
116470c2ee30SGeorge Karpenkov 
116570c2ee30SGeorge Karpenkov   bool changed = false;
116670c2ee30SGeorge Karpenkov   RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
116770c2ee30SGeorge Karpenkov   ConstraintManager &CMgr = state->getConstraintManager();
116803391514SGeorge Karpenkov 
116903391514SGeorge Karpenkov   for (auto &I : B) {
117003391514SGeorge Karpenkov     // Check if the symbol is null stop tracking the symbol.
117103391514SGeorge Karpenkov     ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
117270c2ee30SGeorge Karpenkov     if (AllocFailed.isConstrainedTrue()) {
117370c2ee30SGeorge Karpenkov       changed = true;
117403391514SGeorge Karpenkov       B = RefBFactory.remove(B, I.first);
117570c2ee30SGeorge Karpenkov     }
117670c2ee30SGeorge Karpenkov   }
117770c2ee30SGeorge Karpenkov 
117870c2ee30SGeorge Karpenkov   if (changed)
117970c2ee30SGeorge Karpenkov     state = state->set<RefBindings>(B);
118070c2ee30SGeorge Karpenkov 
118170c2ee30SGeorge Karpenkov   return state;
118270c2ee30SGeorge Karpenkov }
118370c2ee30SGeorge Karpenkov 
checkRegionChanges(ProgramStateRef state,const InvalidatedSymbols * invalidated,ArrayRef<const MemRegion * > ExplicitRegions,ArrayRef<const MemRegion * > Regions,const LocationContext * LCtx,const CallEvent * Call) const1184f153cdfbSGeorge Karpenkov ProgramStateRef RetainCountChecker::checkRegionChanges(
1185f153cdfbSGeorge Karpenkov     ProgramStateRef state, const InvalidatedSymbols *invalidated,
118670c2ee30SGeorge Karpenkov     ArrayRef<const MemRegion *> ExplicitRegions,
1187f153cdfbSGeorge Karpenkov     ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
118870c2ee30SGeorge Karpenkov     const CallEvent *Call) const {
118970c2ee30SGeorge Karpenkov   if (!invalidated)
119070c2ee30SGeorge Karpenkov     return state;
119170c2ee30SGeorge Karpenkov 
11928659b241SZarko Todorovski   llvm::SmallPtrSet<SymbolRef, 8> AllowedSymbols;
119370c2ee30SGeorge Karpenkov 
1194f153cdfbSGeorge Karpenkov   for (const MemRegion *I : ExplicitRegions)
1195f153cdfbSGeorge Karpenkov     if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
11968659b241SZarko Todorovski       AllowedSymbols.insert(SR->getSymbol());
1197f153cdfbSGeorge Karpenkov 
1198f153cdfbSGeorge Karpenkov   for (SymbolRef sym : *invalidated) {
11998659b241SZarko Todorovski     if (AllowedSymbols.count(sym))
120070c2ee30SGeorge Karpenkov       continue;
120170c2ee30SGeorge Karpenkov     // Remove any existing reference-count binding.
120270c2ee30SGeorge Karpenkov     state = removeRefBinding(state, sym);
120370c2ee30SGeorge Karpenkov   }
120470c2ee30SGeorge Karpenkov   return state;
120570c2ee30SGeorge Karpenkov }
120670c2ee30SGeorge Karpenkov 
120770c2ee30SGeorge Karpenkov ProgramStateRef
handleAutoreleaseCounts(ProgramStateRef state,ExplodedNode * Pred,const ProgramPointTag * Tag,CheckerContext & Ctx,SymbolRef Sym,RefVal V,const ReturnStmt * S) const120870c2ee30SGeorge Karpenkov RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
120970c2ee30SGeorge Karpenkov                                             ExplodedNode *Pred,
121070c2ee30SGeorge Karpenkov                                             const ProgramPointTag *Tag,
121170c2ee30SGeorge Karpenkov                                             CheckerContext &Ctx,
121204553e53SGeorge Karpenkov                                             SymbolRef Sym,
121304553e53SGeorge Karpenkov                                             RefVal V,
121404553e53SGeorge Karpenkov                                             const ReturnStmt *S) const {
121570c2ee30SGeorge Karpenkov   unsigned ACnt = V.getAutoreleaseCount();
121670c2ee30SGeorge Karpenkov 
121770c2ee30SGeorge Karpenkov   // No autorelease counts?  Nothing to be done.
121870c2ee30SGeorge Karpenkov   if (!ACnt)
121970c2ee30SGeorge Karpenkov     return state;
122070c2ee30SGeorge Karpenkov 
122170c2ee30SGeorge Karpenkov   unsigned Cnt = V.getCount();
122270c2ee30SGeorge Karpenkov 
122370c2ee30SGeorge Karpenkov   // FIXME: Handle sending 'autorelease' to already released object.
122470c2ee30SGeorge Karpenkov 
122570c2ee30SGeorge Karpenkov   if (V.getKind() == RefVal::ReturnedOwned)
122670c2ee30SGeorge Karpenkov     ++Cnt;
122770c2ee30SGeorge Karpenkov 
122870c2ee30SGeorge Karpenkov   // If we would over-release here, but we know the value came from an ivar,
122970c2ee30SGeorge Karpenkov   // assume it was a strong ivar that's just been relinquished.
123070c2ee30SGeorge Karpenkov   if (ACnt > Cnt &&
123170c2ee30SGeorge Karpenkov       V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
123270c2ee30SGeorge Karpenkov     V = V.releaseViaIvar();
123370c2ee30SGeorge Karpenkov     --ACnt;
123470c2ee30SGeorge Karpenkov   }
123570c2ee30SGeorge Karpenkov 
123670c2ee30SGeorge Karpenkov   if (ACnt <= Cnt) {
123770c2ee30SGeorge Karpenkov     if (ACnt == Cnt) {
123870c2ee30SGeorge Karpenkov       V.clearCounts();
123904553e53SGeorge Karpenkov       if (V.getKind() == RefVal::ReturnedOwned) {
124070c2ee30SGeorge Karpenkov         V = V ^ RefVal::ReturnedNotOwned;
124104553e53SGeorge Karpenkov       } else {
124270c2ee30SGeorge Karpenkov         V = V ^ RefVal::NotOwned;
124304553e53SGeorge Karpenkov       }
124470c2ee30SGeorge Karpenkov     } else {
124570c2ee30SGeorge Karpenkov       V.setCount(V.getCount() - ACnt);
124670c2ee30SGeorge Karpenkov       V.setAutoreleaseCount(0);
124770c2ee30SGeorge Karpenkov     }
124870c2ee30SGeorge Karpenkov     return setRefBinding(state, Sym, V);
124970c2ee30SGeorge Karpenkov   }
125070c2ee30SGeorge Karpenkov 
125170c2ee30SGeorge Karpenkov   // HACK: Ignore retain-count issues on values accessed through ivars,
125270c2ee30SGeorge Karpenkov   // because of cases like this:
125370c2ee30SGeorge Karpenkov   //   [_contentView retain];
125470c2ee30SGeorge Karpenkov   //   [_contentView removeFromSuperview];
125570c2ee30SGeorge Karpenkov   //   [self addSubview:_contentView]; // invalidates 'self'
125670c2ee30SGeorge Karpenkov   //   [_contentView release];
125770c2ee30SGeorge Karpenkov   if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
125870c2ee30SGeorge Karpenkov     return state;
125970c2ee30SGeorge Karpenkov 
126070c2ee30SGeorge Karpenkov   // Woah!  More autorelease counts then retain counts left.
126170c2ee30SGeorge Karpenkov   // Emit hard error.
126270c2ee30SGeorge Karpenkov   V = V ^ RefVal::ErrorOverAutorelease;
126370c2ee30SGeorge Karpenkov   state = setRefBinding(state, Sym, V);
126470c2ee30SGeorge Karpenkov 
126570c2ee30SGeorge Karpenkov   ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
126670c2ee30SGeorge Karpenkov   if (N) {
126770c2ee30SGeorge Karpenkov     SmallString<128> sbuf;
126870c2ee30SGeorge Karpenkov     llvm::raw_svector_ostream os(sbuf);
126970c2ee30SGeorge Karpenkov     os << "Object was autoreleased ";
127070c2ee30SGeorge Karpenkov     if (V.getAutoreleaseCount() > 1)
127170c2ee30SGeorge Karpenkov       os << V.getAutoreleaseCount() << " times but the object ";
127270c2ee30SGeorge Karpenkov     else
127370c2ee30SGeorge Karpenkov       os << "but ";
127470c2ee30SGeorge Karpenkov     os << "has a +" << V.getCount() << " retain count";
127570c2ee30SGeorge Karpenkov 
127670c2ee30SGeorge Karpenkov     const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
12775192783bSKirstóf Umann     auto R = std::make_unique<RefCountReport>(*OverAutorelease, LOpts, N, Sym,
1278717c4c0eSGeorge Karpenkov                                               os.str());
127904553e53SGeorge Karpenkov     Ctx.emitReport(std::move(R));
128070c2ee30SGeorge Karpenkov   }
128170c2ee30SGeorge Karpenkov 
128270c2ee30SGeorge Karpenkov   return nullptr;
128370c2ee30SGeorge Karpenkov }
128470c2ee30SGeorge Karpenkov 
128570c2ee30SGeorge Karpenkov ProgramStateRef
handleSymbolDeath(ProgramStateRef state,SymbolRef sid,RefVal V,SmallVectorImpl<SymbolRef> & Leaked) const128670c2ee30SGeorge Karpenkov RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
128770c2ee30SGeorge Karpenkov                                       SymbolRef sid, RefVal V,
128870c2ee30SGeorge Karpenkov                                     SmallVectorImpl<SymbolRef> &Leaked) const {
128970c2ee30SGeorge Karpenkov   bool hasLeak;
129070c2ee30SGeorge Karpenkov 
129170c2ee30SGeorge Karpenkov   // HACK: Ignore retain-count issues on values accessed through ivars,
129270c2ee30SGeorge Karpenkov   // because of cases like this:
129370c2ee30SGeorge Karpenkov   //   [_contentView retain];
129470c2ee30SGeorge Karpenkov   //   [_contentView removeFromSuperview];
129570c2ee30SGeorge Karpenkov   //   [self addSubview:_contentView]; // invalidates 'self'
129670c2ee30SGeorge Karpenkov   //   [_contentView release];
129770c2ee30SGeorge Karpenkov   if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
129870c2ee30SGeorge Karpenkov     hasLeak = false;
129970c2ee30SGeorge Karpenkov   else if (V.isOwned())
130070c2ee30SGeorge Karpenkov     hasLeak = true;
130170c2ee30SGeorge Karpenkov   else if (V.isNotOwned() || V.isReturnedOwned())
130270c2ee30SGeorge Karpenkov     hasLeak = (V.getCount() > 0);
130370c2ee30SGeorge Karpenkov   else
130470c2ee30SGeorge Karpenkov     hasLeak = false;
130570c2ee30SGeorge Karpenkov 
130670c2ee30SGeorge Karpenkov   if (!hasLeak)
130770c2ee30SGeorge Karpenkov     return removeRefBinding(state, sid);
130870c2ee30SGeorge Karpenkov 
130970c2ee30SGeorge Karpenkov   Leaked.push_back(sid);
131070c2ee30SGeorge Karpenkov   return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
131170c2ee30SGeorge Karpenkov }
131270c2ee30SGeorge Karpenkov 
131370c2ee30SGeorge Karpenkov ExplodedNode *
processLeaks(ProgramStateRef state,SmallVectorImpl<SymbolRef> & Leaked,CheckerContext & Ctx,ExplodedNode * Pred) const131470c2ee30SGeorge Karpenkov RetainCountChecker::processLeaks(ProgramStateRef state,
131570c2ee30SGeorge Karpenkov                                  SmallVectorImpl<SymbolRef> &Leaked,
131670c2ee30SGeorge Karpenkov                                  CheckerContext &Ctx,
131770c2ee30SGeorge Karpenkov                                  ExplodedNode *Pred) const {
131870c2ee30SGeorge Karpenkov   // Generate an intermediate node representing the leak point.
131970c2ee30SGeorge Karpenkov   ExplodedNode *N = Ctx.addTransition(state, Pred);
1320f153cdfbSGeorge Karpenkov   const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
132170c2ee30SGeorge Karpenkov 
132270c2ee30SGeorge Karpenkov   if (N) {
1323f153cdfbSGeorge Karpenkov     for (SymbolRef L : Leaked) {
13245192783bSKirstóf Umann       const RefCountBug &BT = Pred ? *LeakWithinFunction : *LeakAtReturn;
13252b3d49b6SJonas Devlieghere       Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
132670c2ee30SGeorge Karpenkov     }
132770c2ee30SGeorge Karpenkov   }
132870c2ee30SGeorge Karpenkov 
132970c2ee30SGeorge Karpenkov   return N;
133070c2ee30SGeorge Karpenkov }
133170c2ee30SGeorge Karpenkov 
checkBeginFunction(CheckerContext & Ctx) const133270c2ee30SGeorge Karpenkov void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
133370c2ee30SGeorge Karpenkov   if (!Ctx.inTopFrame())
133470c2ee30SGeorge Karpenkov     return;
133570c2ee30SGeorge Karpenkov 
1336c4d6b93dSGeorge Karpenkov   RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
133770c2ee30SGeorge Karpenkov   const LocationContext *LCtx = Ctx.getLocationContext();
133877eae6d4SGeorge Karpenkov   const Decl *D = LCtx->getDecl();
133977eae6d4SGeorge Karpenkov   Optional<AnyCall> C = AnyCall::forDecl(D);
134070c2ee30SGeorge Karpenkov 
134177eae6d4SGeorge Karpenkov   if (!C || SmrMgr.isTrustedReferenceCountImplementation(D))
134270c2ee30SGeorge Karpenkov     return;
134370c2ee30SGeorge Karpenkov 
134470c2ee30SGeorge Karpenkov   ProgramStateRef state = Ctx.getState();
134577eae6d4SGeorge Karpenkov   const RetainSummary *FunctionSummary = SmrMgr.getSummary(*C);
134670c2ee30SGeorge Karpenkov   ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
134770c2ee30SGeorge Karpenkov 
134877eae6d4SGeorge Karpenkov   for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) {
134977eae6d4SGeorge Karpenkov     const ParmVarDecl *Param = C->parameters()[idx];
135070c2ee30SGeorge Karpenkov     SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
135170c2ee30SGeorge Karpenkov 
135270c2ee30SGeorge Karpenkov     QualType Ty = Param->getType();
135370c2ee30SGeorge Karpenkov     const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
1354d37ff4e8SGeorge Karpenkov     if (AE) {
1355d37ff4e8SGeorge Karpenkov       ObjKind K = AE->getObjKind();
1356d37ff4e8SGeorge Karpenkov       if (K == ObjKind::Generalized || K == ObjKind::OS ||
1357d37ff4e8SGeorge Karpenkov           (TrackNSCFStartParam && (K == ObjKind::ObjC || K == ObjKind::CF))) {
1358d37ff4e8SGeorge Karpenkov         RefVal NewVal = AE->getKind() == DecRef ? RefVal::makeOwned(K, Ty)
1359d37ff4e8SGeorge Karpenkov                                                 : RefVal::makeNotOwned(K, Ty);
1360d37ff4e8SGeorge Karpenkov         state = setRefBinding(state, Sym, NewVal);
1361d37ff4e8SGeorge Karpenkov       }
136270c2ee30SGeorge Karpenkov     }
136370c2ee30SGeorge Karpenkov   }
136470c2ee30SGeorge Karpenkov 
136570c2ee30SGeorge Karpenkov   Ctx.addTransition(state);
136670c2ee30SGeorge Karpenkov }
136770c2ee30SGeorge Karpenkov 
checkEndFunction(const ReturnStmt * RS,CheckerContext & Ctx) const136870c2ee30SGeorge Karpenkov void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
136970c2ee30SGeorge Karpenkov                                           CheckerContext &Ctx) const {
137004553e53SGeorge Karpenkov   ExplodedNode *Pred = processReturn(RS, Ctx);
137104553e53SGeorge Karpenkov 
137204553e53SGeorge Karpenkov   // Created state cached out.
137304553e53SGeorge Karpenkov   if (!Pred) {
137404553e53SGeorge Karpenkov     return;
137504553e53SGeorge Karpenkov   }
137604553e53SGeorge Karpenkov 
137704553e53SGeorge Karpenkov   ProgramStateRef state = Pred->getState();
137870c2ee30SGeorge Karpenkov   RefBindingsTy B = state->get<RefBindings>();
137970c2ee30SGeorge Karpenkov 
138070c2ee30SGeorge Karpenkov   // Don't process anything within synthesized bodies.
138170c2ee30SGeorge Karpenkov   const LocationContext *LCtx = Pred->getLocationContext();
138270c2ee30SGeorge Karpenkov   if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
138370c2ee30SGeorge Karpenkov     assert(!LCtx->inTopFrame());
138470c2ee30SGeorge Karpenkov     return;
138570c2ee30SGeorge Karpenkov   }
138670c2ee30SGeorge Karpenkov 
138703391514SGeorge Karpenkov   for (auto &I : B) {
138870c2ee30SGeorge Karpenkov     state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx,
138903391514SGeorge Karpenkov                                     I.first, I.second);
139070c2ee30SGeorge Karpenkov     if (!state)
139170c2ee30SGeorge Karpenkov       return;
139270c2ee30SGeorge Karpenkov   }
139370c2ee30SGeorge Karpenkov 
139470c2ee30SGeorge Karpenkov   // If the current LocationContext has a parent, don't check for leaks.
139570c2ee30SGeorge Karpenkov   // We will do that later.
139670c2ee30SGeorge Karpenkov   // FIXME: we should instead check for imbalances of the retain/releases,
139770c2ee30SGeorge Karpenkov   // and suggest annotations.
139870c2ee30SGeorge Karpenkov   if (LCtx->getParent())
139970c2ee30SGeorge Karpenkov     return;
140070c2ee30SGeorge Karpenkov 
140170c2ee30SGeorge Karpenkov   B = state->get<RefBindings>();
140270c2ee30SGeorge Karpenkov   SmallVector<SymbolRef, 10> Leaked;
140370c2ee30SGeorge Karpenkov 
140403391514SGeorge Karpenkov   for (auto &I : B)
140503391514SGeorge Karpenkov     state = handleSymbolDeath(state, I.first, I.second, Leaked);
140670c2ee30SGeorge Karpenkov 
140770c2ee30SGeorge Karpenkov   processLeaks(state, Leaked, Ctx, Pred);
140870c2ee30SGeorge Karpenkov }
140970c2ee30SGeorge Karpenkov 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const141070c2ee30SGeorge Karpenkov void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
141170c2ee30SGeorge Karpenkov                                           CheckerContext &C) const {
141270c2ee30SGeorge Karpenkov   ExplodedNode *Pred = C.getPredecessor();
141370c2ee30SGeorge Karpenkov 
141470c2ee30SGeorge Karpenkov   ProgramStateRef state = C.getState();
141570c2ee30SGeorge Karpenkov   SmallVector<SymbolRef, 10> Leaked;
141670c2ee30SGeorge Karpenkov 
141770c2ee30SGeorge Karpenkov   // Update counts from autorelease pools
1418bbc6d682SArtem Dergachev   for (const auto &I: state->get<RefBindings>()) {
1419bbc6d682SArtem Dergachev     SymbolRef Sym = I.first;
1420bbc6d682SArtem Dergachev     if (SymReaper.isDead(Sym)) {
142165b4d7ddSArtem Dergachev       static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease");
1422bbc6d682SArtem Dergachev       const RefVal &V = I.second;
1423bbc6d682SArtem Dergachev       state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V);
142470c2ee30SGeorge Karpenkov       if (!state)
142570c2ee30SGeorge Karpenkov         return;
142670c2ee30SGeorge Karpenkov 
142770c2ee30SGeorge Karpenkov       // Fetch the new reference count from the state, and use it to handle
142870c2ee30SGeorge Karpenkov       // this symbol.
1429bbc6d682SArtem Dergachev       state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
143070c2ee30SGeorge Karpenkov     }
143170c2ee30SGeorge Karpenkov   }
143270c2ee30SGeorge Karpenkov 
143370c2ee30SGeorge Karpenkov   if (Leaked.empty()) {
143470c2ee30SGeorge Karpenkov     C.addTransition(state);
143570c2ee30SGeorge Karpenkov     return;
143670c2ee30SGeorge Karpenkov   }
143770c2ee30SGeorge Karpenkov 
143870c2ee30SGeorge Karpenkov   Pred = processLeaks(state, Leaked, C, Pred);
143970c2ee30SGeorge Karpenkov 
144070c2ee30SGeorge Karpenkov   // Did we cache out?
144170c2ee30SGeorge Karpenkov   if (!Pred)
144270c2ee30SGeorge Karpenkov     return;
144370c2ee30SGeorge Karpenkov 
144470c2ee30SGeorge Karpenkov   // Now generate a new node that nukes the old bindings.
144570c2ee30SGeorge Karpenkov   // The only bindings left at this point are the leaked symbols.
144670c2ee30SGeorge Karpenkov   RefBindingsTy::Factory &F = state->get_context<RefBindings>();
1447f153cdfbSGeorge Karpenkov   RefBindingsTy B = state->get<RefBindings>();
144870c2ee30SGeorge Karpenkov 
1449f153cdfbSGeorge Karpenkov   for (SymbolRef L : Leaked)
1450f153cdfbSGeorge Karpenkov     B = F.remove(B, L);
145170c2ee30SGeorge Karpenkov 
145270c2ee30SGeorge Karpenkov   state = state->set<RefBindings>(B);
145370c2ee30SGeorge Karpenkov   C.addTransition(state, Pred);
145470c2ee30SGeorge Karpenkov }
145570c2ee30SGeorge Karpenkov 
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const145670c2ee30SGeorge Karpenkov void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
145770c2ee30SGeorge Karpenkov                                     const char *NL, const char *Sep) const {
145870c2ee30SGeorge Karpenkov 
145970c2ee30SGeorge Karpenkov   RefBindingsTy B = State->get<RefBindings>();
146070c2ee30SGeorge Karpenkov 
146170c2ee30SGeorge Karpenkov   if (B.isEmpty())
146270c2ee30SGeorge Karpenkov     return;
146370c2ee30SGeorge Karpenkov 
146470c2ee30SGeorge Karpenkov   Out << Sep << NL;
146570c2ee30SGeorge Karpenkov 
146603391514SGeorge Karpenkov   for (auto &I : B) {
146703391514SGeorge Karpenkov     Out << I.first << " : ";
146803391514SGeorge Karpenkov     I.second.print(Out);
146970c2ee30SGeorge Karpenkov     Out << NL;
147070c2ee30SGeorge Karpenkov   }
147170c2ee30SGeorge Karpenkov }
147270c2ee30SGeorge Karpenkov 
147370c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
147470c2ee30SGeorge Karpenkov // Checker registration.
147570c2ee30SGeorge Karpenkov //===----------------------------------------------------------------------===//
147670c2ee30SGeorge Karpenkov 
14775192783bSKirstóf Umann std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::DeallocSentTag;
14785192783bSKirstóf Umann std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::CastFailTag;
14795192783bSKirstóf Umann 
registerRetainCountBase(CheckerManager & Mgr)14808fd74ebfSKristof Umann void ento::registerRetainCountBase(CheckerManager &Mgr) {
14815192783bSKirstóf Umann   auto *Chk = Mgr.registerChecker<RetainCountChecker>();
14825192783bSKirstóf Umann   Chk->DeallocSentTag =
14835192783bSKirstóf Umann       std::make_unique<CheckerProgramPointTag>(Chk, "DeallocSent");
14845192783bSKirstóf Umann   Chk->CastFailTag =
14855192783bSKirstóf Umann       std::make_unique<CheckerProgramPointTag>(Chk, "DynamicCastFail");
14868fd74ebfSKristof Umann }
14878fd74ebfSKristof Umann 
shouldRegisterRetainCountBase(const CheckerManager & mgr)1488bda3dd0dSKirstóf Umann bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) {
14898fd74ebfSKristof Umann   return true;
14908fd74ebfSKristof Umann }
registerRetainCountChecker(CheckerManager & Mgr)149170c2ee30SGeorge Karpenkov void ento::registerRetainCountChecker(CheckerManager &Mgr) {
1492204bf2bbSKristof Umann   auto *Chk = Mgr.getChecker<RetainCountChecker>();
149327db3307SGeorge Karpenkov   Chk->TrackObjCAndCFObjects = true;
14946f543184SKirstóf Umann   Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
14956f543184SKirstóf Umann       Mgr.getCurrentCheckerName(), "TrackNSCFStartParam");
14965192783bSKirstóf Umann 
14975192783bSKirstóf Umann #define INIT_BUGTYPE(KIND)                                                     \
14985192783bSKirstóf Umann   Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(),       \
14995192783bSKirstóf Umann                                             RefCountBug::KIND);
15005192783bSKirstóf Umann   // TODO: Ideally, we should have a checker for each of these bug types.
15015192783bSKirstóf Umann   INIT_BUGTYPE(UseAfterRelease)
15025192783bSKirstóf Umann   INIT_BUGTYPE(ReleaseNotOwned)
15035192783bSKirstóf Umann   INIT_BUGTYPE(DeallocNotOwned)
15045192783bSKirstóf Umann   INIT_BUGTYPE(FreeNotOwned)
15055192783bSKirstóf Umann   INIT_BUGTYPE(OverAutorelease)
15065192783bSKirstóf Umann   INIT_BUGTYPE(ReturnNotOwnedForOwned)
15075192783bSKirstóf Umann   INIT_BUGTYPE(LeakWithinFunction)
15085192783bSKirstóf Umann   INIT_BUGTYPE(LeakAtReturn)
15095192783bSKirstóf Umann #undef INIT_BUGTYPE
151027db3307SGeorge Karpenkov }
1511c83b0ddaSKristof Umann 
shouldRegisterRetainCountChecker(const CheckerManager & mgr)1512bda3dd0dSKirstóf Umann bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) {
1513058a7a45SKristof Umann   return true;
1514058a7a45SKristof Umann }
1515058a7a45SKristof Umann 
registerOSObjectRetainCountChecker(CheckerManager & Mgr)151627db3307SGeorge Karpenkov void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
1517204bf2bbSKristof Umann   auto *Chk = Mgr.getChecker<RetainCountChecker>();
151827db3307SGeorge Karpenkov   Chk->TrackOSObjects = true;
15195192783bSKirstóf Umann 
15205192783bSKirstóf Umann   // FIXME: We want bug reports to always have the same checker name associated
15215192783bSKirstóf Umann   // with them, yet here, if RetainCountChecker is disabled but
15225192783bSKirstóf Umann   // OSObjectRetainCountChecker is enabled, the checker names will be different.
15235192783bSKirstóf Umann   // This hack will make it so that the checker name depends on which checker is
15245192783bSKirstóf Umann   // enabled rather than on the registration order.
15255192783bSKirstóf Umann   // For the most part, we want **non-hidden checkers** to be associated with
15265192783bSKirstóf Umann   // diagnostics, and **hidden checker options** with the fine-tuning of
15275192783bSKirstóf Umann   // modeling. Following this logic, OSObjectRetainCountChecker should be the
15285192783bSKirstóf Umann   // latter, but we can't just remove it for backward compatibility reasons.
15295192783bSKirstóf Umann #define LAZY_INIT_BUGTYPE(KIND)                                                \
15305192783bSKirstóf Umann   if (!Chk->KIND)                                                              \
15315192783bSKirstóf Umann     Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(),     \
15325192783bSKirstóf Umann                                               RefCountBug::KIND);
15335192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(UseAfterRelease)
15345192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(ReleaseNotOwned)
15355192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(DeallocNotOwned)
15365192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(FreeNotOwned)
15375192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(OverAutorelease)
15385192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(ReturnNotOwnedForOwned)
15395192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(LeakWithinFunction)
15405192783bSKirstóf Umann   LAZY_INIT_BUGTYPE(LeakAtReturn)
15415192783bSKirstóf Umann #undef LAZY_INIT_BUGTYPE
154270c2ee30SGeorge Karpenkov }
1543058a7a45SKristof Umann 
shouldRegisterOSObjectRetainCountChecker(const CheckerManager & mgr)1544bda3dd0dSKirstóf Umann bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) {
1545058a7a45SKristof Umann   return true;
1546058a7a45SKristof Umann }
1547