17330f729Sjoerg //==-- RetainCountChecker.cpp - Checks for leaks and other issues -*- C++ -*--//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file defines the methods for RetainCountChecker, which implements
107330f729Sjoerg // a reference count checker for Core Foundation and Cocoa on (Mac OS X).
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg
147330f729Sjoerg #include "RetainCountChecker.h"
15*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
167330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
177330f729Sjoerg
187330f729Sjoerg using namespace clang;
197330f729Sjoerg using namespace ento;
207330f729Sjoerg using namespace retaincountchecker;
217330f729Sjoerg
227330f729Sjoerg REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
237330f729Sjoerg
247330f729Sjoerg namespace clang {
257330f729Sjoerg namespace ento {
267330f729Sjoerg namespace retaincountchecker {
277330f729Sjoerg
getRefBinding(ProgramStateRef State,SymbolRef Sym)287330f729Sjoerg const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) {
297330f729Sjoerg return State->get<RefBindings>(Sym);
307330f729Sjoerg }
317330f729Sjoerg
327330f729Sjoerg } // end namespace retaincountchecker
337330f729Sjoerg } // end namespace ento
347330f729Sjoerg } // end namespace clang
357330f729Sjoerg
setRefBinding(ProgramStateRef State,SymbolRef Sym,RefVal Val)367330f729Sjoerg static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym,
377330f729Sjoerg RefVal Val) {
387330f729Sjoerg assert(Sym != nullptr);
397330f729Sjoerg return State->set<RefBindings>(Sym, Val);
407330f729Sjoerg }
417330f729Sjoerg
removeRefBinding(ProgramStateRef State,SymbolRef Sym)427330f729Sjoerg static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) {
437330f729Sjoerg return State->remove<RefBindings>(Sym);
447330f729Sjoerg }
457330f729Sjoerg
print(raw_ostream & Out) const467330f729Sjoerg void RefVal::print(raw_ostream &Out) const {
477330f729Sjoerg if (!T.isNull())
487330f729Sjoerg Out << "Tracked " << T.getAsString() << " | ";
497330f729Sjoerg
507330f729Sjoerg switch (getKind()) {
517330f729Sjoerg default: llvm_unreachable("Invalid RefVal kind");
527330f729Sjoerg case Owned: {
537330f729Sjoerg Out << "Owned";
547330f729Sjoerg unsigned cnt = getCount();
557330f729Sjoerg if (cnt) Out << " (+ " << cnt << ")";
567330f729Sjoerg break;
577330f729Sjoerg }
587330f729Sjoerg
597330f729Sjoerg case NotOwned: {
607330f729Sjoerg Out << "NotOwned";
617330f729Sjoerg unsigned cnt = getCount();
627330f729Sjoerg if (cnt) Out << " (+ " << cnt << ")";
637330f729Sjoerg break;
647330f729Sjoerg }
657330f729Sjoerg
667330f729Sjoerg case ReturnedOwned: {
677330f729Sjoerg Out << "ReturnedOwned";
687330f729Sjoerg unsigned cnt = getCount();
697330f729Sjoerg if (cnt) Out << " (+ " << cnt << ")";
707330f729Sjoerg break;
717330f729Sjoerg }
727330f729Sjoerg
737330f729Sjoerg case ReturnedNotOwned: {
747330f729Sjoerg Out << "ReturnedNotOwned";
757330f729Sjoerg unsigned cnt = getCount();
767330f729Sjoerg if (cnt) Out << " (+ " << cnt << ")";
777330f729Sjoerg break;
787330f729Sjoerg }
797330f729Sjoerg
807330f729Sjoerg case Released:
817330f729Sjoerg Out << "Released";
827330f729Sjoerg break;
837330f729Sjoerg
847330f729Sjoerg case ErrorDeallocNotOwned:
857330f729Sjoerg Out << "-dealloc (not-owned)";
867330f729Sjoerg break;
877330f729Sjoerg
887330f729Sjoerg case ErrorLeak:
897330f729Sjoerg Out << "Leaked";
907330f729Sjoerg break;
917330f729Sjoerg
927330f729Sjoerg case ErrorLeakReturned:
937330f729Sjoerg Out << "Leaked (Bad naming)";
947330f729Sjoerg break;
957330f729Sjoerg
967330f729Sjoerg case ErrorUseAfterRelease:
977330f729Sjoerg Out << "Use-After-Release [ERROR]";
987330f729Sjoerg break;
997330f729Sjoerg
1007330f729Sjoerg case ErrorReleaseNotOwned:
1017330f729Sjoerg Out << "Release of Not-Owned [ERROR]";
1027330f729Sjoerg break;
1037330f729Sjoerg
1047330f729Sjoerg case RefVal::ErrorOverAutorelease:
1057330f729Sjoerg Out << "Over-autoreleased";
1067330f729Sjoerg break;
1077330f729Sjoerg
1087330f729Sjoerg case RefVal::ErrorReturnedNotOwned:
1097330f729Sjoerg Out << "Non-owned object returned instead of owned";
1107330f729Sjoerg break;
1117330f729Sjoerg }
1127330f729Sjoerg
1137330f729Sjoerg switch (getIvarAccessHistory()) {
1147330f729Sjoerg case IvarAccessHistory::None:
1157330f729Sjoerg break;
1167330f729Sjoerg case IvarAccessHistory::AccessedDirectly:
1177330f729Sjoerg Out << " [direct ivar access]";
1187330f729Sjoerg break;
1197330f729Sjoerg case IvarAccessHistory::ReleasedAfterDirectAccess:
1207330f729Sjoerg Out << " [released after direct ivar access]";
1217330f729Sjoerg }
1227330f729Sjoerg
1237330f729Sjoerg if (ACnt) {
1247330f729Sjoerg Out << " [autorelease -" << ACnt << ']';
1257330f729Sjoerg }
1267330f729Sjoerg }
1277330f729Sjoerg
1287330f729Sjoerg namespace {
1297330f729Sjoerg class StopTrackingCallback final : public SymbolVisitor {
1307330f729Sjoerg ProgramStateRef state;
1317330f729Sjoerg public:
StopTrackingCallback(ProgramStateRef st)1327330f729Sjoerg StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
getState() const1337330f729Sjoerg ProgramStateRef getState() const { return state; }
1347330f729Sjoerg
VisitSymbol(SymbolRef sym)1357330f729Sjoerg bool VisitSymbol(SymbolRef sym) override {
1367330f729Sjoerg state = removeRefBinding(state, sym);
1377330f729Sjoerg return true;
1387330f729Sjoerg }
1397330f729Sjoerg };
1407330f729Sjoerg } // end anonymous namespace
1417330f729Sjoerg
1427330f729Sjoerg //===----------------------------------------------------------------------===//
1437330f729Sjoerg // Handle statements that may have an effect on refcounts.
1447330f729Sjoerg //===----------------------------------------------------------------------===//
1457330f729Sjoerg
checkPostStmt(const BlockExpr * BE,CheckerContext & C) const1467330f729Sjoerg void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
1477330f729Sjoerg CheckerContext &C) const {
1487330f729Sjoerg
1497330f729Sjoerg // Scan the BlockDecRefExprs for any object the retain count checker
1507330f729Sjoerg // may be tracking.
1517330f729Sjoerg if (!BE->getBlockDecl()->hasCaptures())
1527330f729Sjoerg return;
1537330f729Sjoerg
1547330f729Sjoerg ProgramStateRef state = C.getState();
1557330f729Sjoerg auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
1567330f729Sjoerg
1577330f729Sjoerg BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
1587330f729Sjoerg E = R->referenced_vars_end();
1597330f729Sjoerg
1607330f729Sjoerg if (I == E)
1617330f729Sjoerg return;
1627330f729Sjoerg
1637330f729Sjoerg // FIXME: For now we invalidate the tracking of all symbols passed to blocks
1647330f729Sjoerg // via captured variables, even though captured variables result in a copy
1657330f729Sjoerg // and in implicit increment/decrement of a retain count.
1667330f729Sjoerg SmallVector<const MemRegion*, 10> Regions;
1677330f729Sjoerg const LocationContext *LC = C.getLocationContext();
1687330f729Sjoerg MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
1697330f729Sjoerg
1707330f729Sjoerg for ( ; I != E; ++I) {
1717330f729Sjoerg const VarRegion *VR = I.getCapturedRegion();
1727330f729Sjoerg if (VR->getSuperRegion() == R) {
1737330f729Sjoerg VR = MemMgr.getVarRegion(VR->getDecl(), LC);
1747330f729Sjoerg }
1757330f729Sjoerg Regions.push_back(VR);
1767330f729Sjoerg }
1777330f729Sjoerg
1787330f729Sjoerg state = state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
1797330f729Sjoerg C.addTransition(state);
1807330f729Sjoerg }
1817330f729Sjoerg
checkPostStmt(const CastExpr * CE,CheckerContext & C) const1827330f729Sjoerg void RetainCountChecker::checkPostStmt(const CastExpr *CE,
1837330f729Sjoerg CheckerContext &C) const {
1847330f729Sjoerg const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
1857330f729Sjoerg if (!BE)
1867330f729Sjoerg return;
1877330f729Sjoerg
1887330f729Sjoerg QualType QT = CE->getType();
1897330f729Sjoerg ObjKind K;
1907330f729Sjoerg if (QT->isObjCObjectPointerType()) {
1917330f729Sjoerg K = ObjKind::ObjC;
1927330f729Sjoerg } else {
1937330f729Sjoerg K = ObjKind::CF;
1947330f729Sjoerg }
1957330f729Sjoerg
1967330f729Sjoerg ArgEffect AE = ArgEffect(IncRef, K);
1977330f729Sjoerg
1987330f729Sjoerg switch (BE->getBridgeKind()) {
1997330f729Sjoerg case OBC_Bridge:
2007330f729Sjoerg // Do nothing.
2017330f729Sjoerg return;
2027330f729Sjoerg case OBC_BridgeRetained:
2037330f729Sjoerg AE = AE.withKind(IncRef);
2047330f729Sjoerg break;
2057330f729Sjoerg case OBC_BridgeTransfer:
2067330f729Sjoerg AE = AE.withKind(DecRefBridgedTransferred);
2077330f729Sjoerg break;
2087330f729Sjoerg }
2097330f729Sjoerg
2107330f729Sjoerg ProgramStateRef state = C.getState();
2117330f729Sjoerg SymbolRef Sym = C.getSVal(CE).getAsLocSymbol();
2127330f729Sjoerg if (!Sym)
2137330f729Sjoerg return;
2147330f729Sjoerg const RefVal* T = getRefBinding(state, Sym);
2157330f729Sjoerg if (!T)
2167330f729Sjoerg return;
2177330f729Sjoerg
2187330f729Sjoerg RefVal::Kind hasErr = (RefVal::Kind) 0;
2197330f729Sjoerg state = updateSymbol(state, Sym, *T, AE, hasErr, C);
2207330f729Sjoerg
2217330f729Sjoerg if (hasErr) {
2227330f729Sjoerg // FIXME: If we get an error during a bridge cast, should we report it?
2237330f729Sjoerg return;
2247330f729Sjoerg }
2257330f729Sjoerg
2267330f729Sjoerg C.addTransition(state);
2277330f729Sjoerg }
2287330f729Sjoerg
processObjCLiterals(CheckerContext & C,const Expr * Ex) const2297330f729Sjoerg void RetainCountChecker::processObjCLiterals(CheckerContext &C,
2307330f729Sjoerg const Expr *Ex) const {
2317330f729Sjoerg ProgramStateRef state = C.getState();
2327330f729Sjoerg const ExplodedNode *pred = C.getPredecessor();
2337330f729Sjoerg for (const Stmt *Child : Ex->children()) {
2347330f729Sjoerg SVal V = pred->getSVal(Child);
2357330f729Sjoerg if (SymbolRef sym = V.getAsSymbol())
2367330f729Sjoerg if (const RefVal* T = getRefBinding(state, sym)) {
2377330f729Sjoerg RefVal::Kind hasErr = (RefVal::Kind) 0;
2387330f729Sjoerg state = updateSymbol(state, sym, *T,
2397330f729Sjoerg ArgEffect(MayEscape, ObjKind::ObjC), hasErr, C);
2407330f729Sjoerg if (hasErr) {
2417330f729Sjoerg processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C);
2427330f729Sjoerg return;
2437330f729Sjoerg }
2447330f729Sjoerg }
2457330f729Sjoerg }
2467330f729Sjoerg
2477330f729Sjoerg // Return the object as autoreleased.
2487330f729Sjoerg // RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC);
2497330f729Sjoerg if (SymbolRef sym =
2507330f729Sjoerg state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
2517330f729Sjoerg QualType ResultTy = Ex->getType();
2527330f729Sjoerg state = setRefBinding(state, sym,
2537330f729Sjoerg RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
2547330f729Sjoerg }
2557330f729Sjoerg
2567330f729Sjoerg C.addTransition(state);
2577330f729Sjoerg }
2587330f729Sjoerg
checkPostStmt(const ObjCArrayLiteral * AL,CheckerContext & C) const2597330f729Sjoerg void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
2607330f729Sjoerg CheckerContext &C) const {
2617330f729Sjoerg // Apply the 'MayEscape' to all values.
2627330f729Sjoerg processObjCLiterals(C, AL);
2637330f729Sjoerg }
2647330f729Sjoerg
checkPostStmt(const ObjCDictionaryLiteral * DL,CheckerContext & C) const2657330f729Sjoerg void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
2667330f729Sjoerg CheckerContext &C) const {
2677330f729Sjoerg // Apply the 'MayEscape' to all keys and values.
2687330f729Sjoerg processObjCLiterals(C, DL);
2697330f729Sjoerg }
2707330f729Sjoerg
checkPostStmt(const ObjCBoxedExpr * Ex,CheckerContext & C) const2717330f729Sjoerg void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
2727330f729Sjoerg CheckerContext &C) const {
2737330f729Sjoerg const ExplodedNode *Pred = C.getPredecessor();
2747330f729Sjoerg ProgramStateRef State = Pred->getState();
2757330f729Sjoerg
2767330f729Sjoerg if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) {
2777330f729Sjoerg QualType ResultTy = Ex->getType();
2787330f729Sjoerg State = setRefBinding(State, Sym,
2797330f729Sjoerg RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
2807330f729Sjoerg }
2817330f729Sjoerg
2827330f729Sjoerg C.addTransition(State);
2837330f729Sjoerg }
2847330f729Sjoerg
checkPostStmt(const ObjCIvarRefExpr * IRE,CheckerContext & C) const2857330f729Sjoerg void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
2867330f729Sjoerg CheckerContext &C) const {
2877330f729Sjoerg Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
2887330f729Sjoerg if (!IVarLoc)
2897330f729Sjoerg return;
2907330f729Sjoerg
2917330f729Sjoerg ProgramStateRef State = C.getState();
2927330f729Sjoerg SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
2937330f729Sjoerg if (!Sym || !dyn_cast_or_null<ObjCIvarRegion>(Sym->getOriginRegion()))
2947330f729Sjoerg return;
2957330f729Sjoerg
2967330f729Sjoerg // Accessing an ivar directly is unusual. If we've done that, be more
2977330f729Sjoerg // forgiving about what the surrounding code is allowed to do.
2987330f729Sjoerg
2997330f729Sjoerg QualType Ty = Sym->getType();
3007330f729Sjoerg ObjKind Kind;
3017330f729Sjoerg if (Ty->isObjCRetainableType())
3027330f729Sjoerg Kind = ObjKind::ObjC;
3037330f729Sjoerg else if (coreFoundation::isCFObjectRef(Ty))
3047330f729Sjoerg Kind = ObjKind::CF;
3057330f729Sjoerg else
3067330f729Sjoerg return;
3077330f729Sjoerg
3087330f729Sjoerg // If the value is already known to be nil, don't bother tracking it.
3097330f729Sjoerg ConstraintManager &CMgr = State->getConstraintManager();
3107330f729Sjoerg if (CMgr.isNull(State, Sym).isConstrainedTrue())
3117330f729Sjoerg return;
3127330f729Sjoerg
3137330f729Sjoerg if (const RefVal *RV = getRefBinding(State, Sym)) {
3147330f729Sjoerg // If we've seen this symbol before, or we're only seeing it now because
3157330f729Sjoerg // of something the analyzer has synthesized, don't do anything.
3167330f729Sjoerg if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None ||
3177330f729Sjoerg isSynthesizedAccessor(C.getStackFrame())) {
3187330f729Sjoerg return;
3197330f729Sjoerg }
3207330f729Sjoerg
3217330f729Sjoerg // Note that this value has been loaded from an ivar.
3227330f729Sjoerg C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
3237330f729Sjoerg return;
3247330f729Sjoerg }
3257330f729Sjoerg
3267330f729Sjoerg RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty);
3277330f729Sjoerg
3287330f729Sjoerg // In a synthesized accessor, the effective retain count is +0.
3297330f729Sjoerg if (isSynthesizedAccessor(C.getStackFrame())) {
3307330f729Sjoerg C.addTransition(setRefBinding(State, Sym, PlusZero));
3317330f729Sjoerg return;
3327330f729Sjoerg }
3337330f729Sjoerg
3347330f729Sjoerg State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
3357330f729Sjoerg C.addTransition(State);
3367330f729Sjoerg }
3377330f729Sjoerg
isReceiverUnconsumedSelf(const CallEvent & Call)3387330f729Sjoerg static bool isReceiverUnconsumedSelf(const CallEvent &Call) {
3397330f729Sjoerg if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
3407330f729Sjoerg
3417330f729Sjoerg // Check if the message is not consumed, we know it will not be used in
3427330f729Sjoerg // an assignment, ex: "self = [super init]".
3437330f729Sjoerg return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
3447330f729Sjoerg !Call.getLocationContext()
3457330f729Sjoerg ->getAnalysisDeclContext()
3467330f729Sjoerg ->getParentMap()
3477330f729Sjoerg .isConsumedExpr(Call.getOriginExpr());
3487330f729Sjoerg }
3497330f729Sjoerg return false;
3507330f729Sjoerg }
3517330f729Sjoerg
getSummary(RetainSummaryManager & Summaries,const CallEvent & Call,QualType ReceiverType)3527330f729Sjoerg const static RetainSummary *getSummary(RetainSummaryManager &Summaries,
3537330f729Sjoerg const CallEvent &Call,
3547330f729Sjoerg QualType ReceiverType) {
3557330f729Sjoerg const Expr *CE = Call.getOriginExpr();
3567330f729Sjoerg AnyCall C =
3577330f729Sjoerg CE ? *AnyCall::forExpr(CE)
3587330f729Sjoerg : AnyCall(cast<CXXDestructorDecl>(Call.getDecl()));
3597330f729Sjoerg return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
3607330f729Sjoerg isReceiverUnconsumedSelf(Call), ReceiverType);
3617330f729Sjoerg }
3627330f729Sjoerg
checkPostCall(const CallEvent & Call,CheckerContext & C) const3637330f729Sjoerg void RetainCountChecker::checkPostCall(const CallEvent &Call,
3647330f729Sjoerg CheckerContext &C) const {
3657330f729Sjoerg RetainSummaryManager &Summaries = getSummaryManager(C);
3667330f729Sjoerg
3677330f729Sjoerg // Leave null if no receiver.
3687330f729Sjoerg QualType ReceiverType;
3697330f729Sjoerg if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
3707330f729Sjoerg if (MC->isInstanceMessage()) {
3717330f729Sjoerg SVal ReceiverV = MC->getReceiverSVal();
3727330f729Sjoerg if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
3737330f729Sjoerg if (const RefVal *T = getRefBinding(C.getState(), Sym))
3747330f729Sjoerg ReceiverType = T->getType();
3757330f729Sjoerg }
3767330f729Sjoerg }
3777330f729Sjoerg
3787330f729Sjoerg const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType);
3797330f729Sjoerg
3807330f729Sjoerg if (C.wasInlined) {
3817330f729Sjoerg processSummaryOfInlined(*Summ, Call, C);
3827330f729Sjoerg return;
3837330f729Sjoerg }
3847330f729Sjoerg checkSummary(*Summ, Call, C);
3857330f729Sjoerg }
3867330f729Sjoerg
3877330f729Sjoerg /// GetReturnType - Used to get the return type of a message expression or
3887330f729Sjoerg /// function call with the intention of affixing that type to a tracked symbol.
3897330f729Sjoerg /// While the return type can be queried directly from RetEx, when
3907330f729Sjoerg /// invoking class methods we augment to the return type to be that of
3917330f729Sjoerg /// a pointer to the class (as opposed it just being id).
3927330f729Sjoerg // FIXME: We may be able to do this with related result types instead.
3937330f729Sjoerg // This function is probably overestimating.
GetReturnType(const Expr * RetE,ASTContext & Ctx)3947330f729Sjoerg static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
3957330f729Sjoerg QualType RetTy = RetE->getType();
3967330f729Sjoerg // If RetE is not a message expression just return its type.
3977330f729Sjoerg // If RetE is a message expression, return its types if it is something
3987330f729Sjoerg /// more specific than id.
3997330f729Sjoerg if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
4007330f729Sjoerg if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
4017330f729Sjoerg if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
4027330f729Sjoerg PT->isObjCClassType()) {
4037330f729Sjoerg // At this point we know the return type of the message expression is
4047330f729Sjoerg // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
4057330f729Sjoerg // is a call to a class method whose type we can resolve. In such
4067330f729Sjoerg // cases, promote the return type to XXX* (where XXX is the class).
4077330f729Sjoerg const ObjCInterfaceDecl *D = ME->getReceiverInterface();
4087330f729Sjoerg return !D ? RetTy :
4097330f729Sjoerg Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D));
4107330f729Sjoerg }
4117330f729Sjoerg
4127330f729Sjoerg return RetTy;
4137330f729Sjoerg }
4147330f729Sjoerg
refValFromRetEffect(RetEffect RE,QualType ResultTy)4157330f729Sjoerg static Optional<RefVal> refValFromRetEffect(RetEffect RE,
4167330f729Sjoerg QualType ResultTy) {
4177330f729Sjoerg if (RE.isOwned()) {
4187330f729Sjoerg return RefVal::makeOwned(RE.getObjKind(), ResultTy);
4197330f729Sjoerg } else if (RE.notOwned()) {
4207330f729Sjoerg return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
4217330f729Sjoerg }
4227330f729Sjoerg
4237330f729Sjoerg return None;
4247330f729Sjoerg }
4257330f729Sjoerg
isPointerToObject(QualType QT)4267330f729Sjoerg static bool isPointerToObject(QualType QT) {
4277330f729Sjoerg QualType PT = QT->getPointeeType();
4287330f729Sjoerg if (!PT.isNull())
4297330f729Sjoerg if (PT->getAsCXXRecordDecl())
4307330f729Sjoerg return true;
4317330f729Sjoerg return false;
4327330f729Sjoerg }
4337330f729Sjoerg
4347330f729Sjoerg /// Whether the tracked value should be escaped on a given call.
4357330f729Sjoerg /// OSObjects are escaped when passed to void * / etc.
shouldEscapeOSArgumentOnCall(const CallEvent & CE,unsigned ArgIdx,const RefVal * TrackedValue)4367330f729Sjoerg static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx,
4377330f729Sjoerg const RefVal *TrackedValue) {
4387330f729Sjoerg if (TrackedValue->getObjKind() != ObjKind::OS)
4397330f729Sjoerg return false;
4407330f729Sjoerg if (ArgIdx >= CE.parameters().size())
4417330f729Sjoerg return false;
4427330f729Sjoerg return !isPointerToObject(CE.parameters()[ArgIdx]->getType());
4437330f729Sjoerg }
4447330f729Sjoerg
4457330f729Sjoerg // We don't always get the exact modeling of the function with regards to the
4467330f729Sjoerg // retain count checker even when the function is inlined. For example, we need
4477330f729Sjoerg // to stop tracking the symbols which were marked with StopTrackingHard.
processSummaryOfInlined(const RetainSummary & Summ,const CallEvent & CallOrMsg,CheckerContext & C) const4487330f729Sjoerg void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
4497330f729Sjoerg const CallEvent &CallOrMsg,
4507330f729Sjoerg CheckerContext &C) const {
4517330f729Sjoerg ProgramStateRef state = C.getState();
4527330f729Sjoerg
4537330f729Sjoerg // Evaluate the effect of the arguments.
4547330f729Sjoerg for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
4557330f729Sjoerg SVal V = CallOrMsg.getArgSVal(idx);
4567330f729Sjoerg
4577330f729Sjoerg if (SymbolRef Sym = V.getAsLocSymbol()) {
4587330f729Sjoerg bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard;
4597330f729Sjoerg if (const RefVal *T = getRefBinding(state, Sym))
4607330f729Sjoerg if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
4617330f729Sjoerg ShouldRemoveBinding = true;
4627330f729Sjoerg
4637330f729Sjoerg if (ShouldRemoveBinding)
4647330f729Sjoerg state = removeRefBinding(state, Sym);
4657330f729Sjoerg }
4667330f729Sjoerg }
4677330f729Sjoerg
4687330f729Sjoerg // Evaluate the effect on the message receiver.
4697330f729Sjoerg if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
4707330f729Sjoerg if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
4717330f729Sjoerg if (Summ.getReceiverEffect().getKind() == StopTrackingHard) {
4727330f729Sjoerg state = removeRefBinding(state, Sym);
4737330f729Sjoerg }
4747330f729Sjoerg }
4757330f729Sjoerg }
4767330f729Sjoerg
4777330f729Sjoerg // Consult the summary for the return value.
4787330f729Sjoerg RetEffect RE = Summ.getRetEffect();
4797330f729Sjoerg
4807330f729Sjoerg if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
4817330f729Sjoerg if (RE.getKind() == RetEffect::NoRetHard)
4827330f729Sjoerg state = removeRefBinding(state, Sym);
4837330f729Sjoerg }
4847330f729Sjoerg
4857330f729Sjoerg C.addTransition(state);
4867330f729Sjoerg }
4877330f729Sjoerg
isSmartPtrField(const MemRegion * MR)4887330f729Sjoerg static bool isSmartPtrField(const MemRegion *MR) {
4897330f729Sjoerg const auto *TR = dyn_cast<TypedValueRegion>(
4907330f729Sjoerg cast<SubRegion>(MR)->getSuperRegion());
4917330f729Sjoerg return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType());
4927330f729Sjoerg }
4937330f729Sjoerg
4947330f729Sjoerg
4957330f729Sjoerg /// A value escapes in these possible cases:
4967330f729Sjoerg ///
4977330f729Sjoerg /// - binding to something that is not a memory region.
4987330f729Sjoerg /// - binding to a memregion that does not have stack storage
4997330f729Sjoerg /// - binding to a variable that has a destructor attached using CleanupAttr
5007330f729Sjoerg ///
5017330f729Sjoerg /// We do not currently model what happens when a symbol is
5027330f729Sjoerg /// assigned to a struct field, unless it is a known smart pointer
5037330f729Sjoerg /// implementation, about which we know that it is inlined.
5047330f729Sjoerg /// FIXME: This could definitely be improved upon.
shouldEscapeRegion(const MemRegion * R)5057330f729Sjoerg static bool shouldEscapeRegion(const MemRegion *R) {
5067330f729Sjoerg if (isSmartPtrField(R))
5077330f729Sjoerg return false;
5087330f729Sjoerg
5097330f729Sjoerg const auto *VR = dyn_cast<VarRegion>(R);
5107330f729Sjoerg
5117330f729Sjoerg if (!R->hasStackStorage() || !VR)
5127330f729Sjoerg return true;
5137330f729Sjoerg
5147330f729Sjoerg const VarDecl *VD = VR->getDecl();
5157330f729Sjoerg if (!VD->hasAttr<CleanupAttr>())
5167330f729Sjoerg return false; // CleanupAttr attaches destructors, which cause escaping.
5177330f729Sjoerg return true;
5187330f729Sjoerg }
5197330f729Sjoerg
5207330f729Sjoerg static SmallVector<ProgramStateRef, 2>
updateOutParameters(ProgramStateRef State,const RetainSummary & Summ,const CallEvent & CE)5217330f729Sjoerg updateOutParameters(ProgramStateRef State, const RetainSummary &Summ,
5227330f729Sjoerg const CallEvent &CE) {
5237330f729Sjoerg
5247330f729Sjoerg SVal L = CE.getReturnValue();
5257330f729Sjoerg
5267330f729Sjoerg // Splitting is required to support out parameters,
5277330f729Sjoerg // as out parameters might be created only on the "success" branch.
5287330f729Sjoerg // We want to avoid eagerly splitting unless out parameters are actually
5297330f729Sjoerg // needed.
5307330f729Sjoerg bool SplitNecessary = false;
5317330f729Sjoerg for (auto &P : Summ.getArgEffects())
5327330f729Sjoerg if (P.second.getKind() == RetainedOutParameterOnNonZero ||
5337330f729Sjoerg P.second.getKind() == RetainedOutParameterOnZero)
5347330f729Sjoerg SplitNecessary = true;
5357330f729Sjoerg
5367330f729Sjoerg ProgramStateRef AssumeNonZeroReturn = State;
5377330f729Sjoerg ProgramStateRef AssumeZeroReturn = State;
5387330f729Sjoerg
5397330f729Sjoerg if (SplitNecessary) {
5407330f729Sjoerg if (!CE.getResultType()->isScalarType()) {
5417330f729Sjoerg // Structures cannot be assumed. This probably deserves
5427330f729Sjoerg // a compiler warning for invalid annotations.
5437330f729Sjoerg return {State};
5447330f729Sjoerg }
5457330f729Sjoerg if (auto DL = L.getAs<DefinedOrUnknownSVal>()) {
5467330f729Sjoerg AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true);
5477330f729Sjoerg AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false);
5487330f729Sjoerg }
5497330f729Sjoerg }
5507330f729Sjoerg
5517330f729Sjoerg for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) {
5527330f729Sjoerg SVal ArgVal = CE.getArgSVal(idx);
5537330f729Sjoerg ArgEffect AE = Summ.getArg(idx);
5547330f729Sjoerg
5557330f729Sjoerg auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion());
5567330f729Sjoerg if (!ArgRegion)
5577330f729Sjoerg continue;
5587330f729Sjoerg
5597330f729Sjoerg QualType PointeeTy = ArgRegion->getValueType();
5607330f729Sjoerg SVal PointeeVal = State->getSVal(ArgRegion);
5617330f729Sjoerg SymbolRef Pointee = PointeeVal.getAsLocSymbol();
5627330f729Sjoerg if (!Pointee)
5637330f729Sjoerg continue;
5647330f729Sjoerg
5657330f729Sjoerg if (shouldEscapeRegion(ArgRegion))
5667330f729Sjoerg continue;
5677330f729Sjoerg
5687330f729Sjoerg auto makeNotOwnedParameter = [&](ProgramStateRef St) {
5697330f729Sjoerg return setRefBinding(St, Pointee,
5707330f729Sjoerg RefVal::makeNotOwned(AE.getObjKind(), PointeeTy));
5717330f729Sjoerg };
5727330f729Sjoerg auto makeOwnedParameter = [&](ProgramStateRef St) {
5737330f729Sjoerg return setRefBinding(St, Pointee,
5747330f729Sjoerg RefVal::makeOwned(ObjKind::OS, PointeeTy));
5757330f729Sjoerg };
5767330f729Sjoerg
5777330f729Sjoerg switch (AE.getKind()) {
5787330f729Sjoerg case UnretainedOutParameter:
5797330f729Sjoerg AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
5807330f729Sjoerg AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
5817330f729Sjoerg break;
5827330f729Sjoerg case RetainedOutParameter:
5837330f729Sjoerg AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
5847330f729Sjoerg AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
5857330f729Sjoerg break;
5867330f729Sjoerg case RetainedOutParameterOnNonZero:
5877330f729Sjoerg AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
5887330f729Sjoerg break;
5897330f729Sjoerg case RetainedOutParameterOnZero:
5907330f729Sjoerg AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
5917330f729Sjoerg break;
5927330f729Sjoerg default:
5937330f729Sjoerg break;
5947330f729Sjoerg }
5957330f729Sjoerg }
5967330f729Sjoerg
5977330f729Sjoerg if (SplitNecessary) {
5987330f729Sjoerg return {AssumeNonZeroReturn, AssumeZeroReturn};
5997330f729Sjoerg } else {
6007330f729Sjoerg assert(AssumeZeroReturn == AssumeNonZeroReturn);
6017330f729Sjoerg return {AssumeZeroReturn};
6027330f729Sjoerg }
6037330f729Sjoerg }
6047330f729Sjoerg
checkSummary(const RetainSummary & Summ,const CallEvent & CallOrMsg,CheckerContext & C) const6057330f729Sjoerg void RetainCountChecker::checkSummary(const RetainSummary &Summ,
6067330f729Sjoerg const CallEvent &CallOrMsg,
6077330f729Sjoerg CheckerContext &C) const {
6087330f729Sjoerg ProgramStateRef state = C.getState();
6097330f729Sjoerg
6107330f729Sjoerg // Evaluate the effect of the arguments.
6117330f729Sjoerg RefVal::Kind hasErr = (RefVal::Kind) 0;
6127330f729Sjoerg SourceRange ErrorRange;
6137330f729Sjoerg SymbolRef ErrorSym = nullptr;
6147330f729Sjoerg
6157330f729Sjoerg // Helper tag for providing diagnostics: indicate whether dealloc was sent
6167330f729Sjoerg // at this location.
6177330f729Sjoerg bool DeallocSent = false;
6187330f729Sjoerg
6197330f729Sjoerg for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
6207330f729Sjoerg SVal V = CallOrMsg.getArgSVal(idx);
6217330f729Sjoerg
6227330f729Sjoerg ArgEffect Effect = Summ.getArg(idx);
6237330f729Sjoerg if (SymbolRef Sym = V.getAsLocSymbol()) {
6247330f729Sjoerg if (const RefVal *T = getRefBinding(state, Sym)) {
6257330f729Sjoerg
6267330f729Sjoerg if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
6277330f729Sjoerg Effect = ArgEffect(StopTrackingHard, ObjKind::OS);
6287330f729Sjoerg
6297330f729Sjoerg state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
6307330f729Sjoerg if (hasErr) {
6317330f729Sjoerg ErrorRange = CallOrMsg.getArgSourceRange(idx);
6327330f729Sjoerg ErrorSym = Sym;
6337330f729Sjoerg break;
6347330f729Sjoerg } else if (Effect.getKind() == Dealloc) {
6357330f729Sjoerg DeallocSent = true;
6367330f729Sjoerg }
6377330f729Sjoerg }
6387330f729Sjoerg }
6397330f729Sjoerg }
6407330f729Sjoerg
6417330f729Sjoerg // Evaluate the effect on the message receiver / `this` argument.
6427330f729Sjoerg bool ReceiverIsTracked = false;
6437330f729Sjoerg if (!hasErr) {
6447330f729Sjoerg if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
6457330f729Sjoerg if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
6467330f729Sjoerg if (const RefVal *T = getRefBinding(state, Sym)) {
6477330f729Sjoerg ReceiverIsTracked = true;
6487330f729Sjoerg state = updateSymbol(state, Sym, *T,
6497330f729Sjoerg Summ.getReceiverEffect(), hasErr, C);
6507330f729Sjoerg if (hasErr) {
6517330f729Sjoerg ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
6527330f729Sjoerg ErrorSym = Sym;
6537330f729Sjoerg } else if (Summ.getReceiverEffect().getKind() == Dealloc) {
6547330f729Sjoerg DeallocSent = true;
6557330f729Sjoerg }
6567330f729Sjoerg }
6577330f729Sjoerg }
6587330f729Sjoerg } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
6597330f729Sjoerg if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
6607330f729Sjoerg if (const RefVal *T = getRefBinding(state, Sym)) {
6617330f729Sjoerg state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
6627330f729Sjoerg hasErr, C);
6637330f729Sjoerg if (hasErr) {
6647330f729Sjoerg ErrorRange = MCall->getOriginExpr()->getSourceRange();
6657330f729Sjoerg ErrorSym = Sym;
6667330f729Sjoerg }
6677330f729Sjoerg }
6687330f729Sjoerg }
6697330f729Sjoerg }
6707330f729Sjoerg }
6717330f729Sjoerg
6727330f729Sjoerg // Process any errors.
6737330f729Sjoerg if (hasErr) {
6747330f729Sjoerg processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
6757330f729Sjoerg return;
6767330f729Sjoerg }
6777330f729Sjoerg
6787330f729Sjoerg // Consult the summary for the return value.
6797330f729Sjoerg RetEffect RE = Summ.getRetEffect();
6807330f729Sjoerg
6817330f729Sjoerg if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
6827330f729Sjoerg if (ReceiverIsTracked)
6837330f729Sjoerg RE = getSummaryManager(C).getObjAllocRetEffect();
6847330f729Sjoerg else
6857330f729Sjoerg RE = RetEffect::MakeNoRet();
6867330f729Sjoerg }
6877330f729Sjoerg
6887330f729Sjoerg if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
6897330f729Sjoerg QualType ResultTy = CallOrMsg.getResultType();
6907330f729Sjoerg if (RE.notOwned()) {
6917330f729Sjoerg const Expr *Ex = CallOrMsg.getOriginExpr();
6927330f729Sjoerg assert(Ex);
6937330f729Sjoerg ResultTy = GetReturnType(Ex, C.getASTContext());
6947330f729Sjoerg }
6957330f729Sjoerg if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
6967330f729Sjoerg state = setRefBinding(state, Sym, *updatedRefVal);
6977330f729Sjoerg }
6987330f729Sjoerg
6997330f729Sjoerg SmallVector<ProgramStateRef, 2> Out =
7007330f729Sjoerg updateOutParameters(state, Summ, CallOrMsg);
7017330f729Sjoerg
7027330f729Sjoerg for (ProgramStateRef St : Out) {
7037330f729Sjoerg if (DeallocSent) {
704*e038c9c4Sjoerg C.addTransition(St, C.getPredecessor(), &getDeallocSentTag());
7057330f729Sjoerg } else {
7067330f729Sjoerg C.addTransition(St);
7077330f729Sjoerg }
7087330f729Sjoerg }
7097330f729Sjoerg }
7107330f729Sjoerg
updateSymbol(ProgramStateRef state,SymbolRef sym,RefVal V,ArgEffect AE,RefVal::Kind & hasErr,CheckerContext & C) const7117330f729Sjoerg ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
7127330f729Sjoerg SymbolRef sym, RefVal V,
7137330f729Sjoerg ArgEffect AE,
7147330f729Sjoerg RefVal::Kind &hasErr,
7157330f729Sjoerg CheckerContext &C) const {
7167330f729Sjoerg bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
7177330f729Sjoerg if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) {
7187330f729Sjoerg switch (AE.getKind()) {
7197330f729Sjoerg default:
7207330f729Sjoerg break;
7217330f729Sjoerg case IncRef:
7227330f729Sjoerg AE = AE.withKind(DoNothing);
7237330f729Sjoerg break;
7247330f729Sjoerg case DecRef:
7257330f729Sjoerg AE = AE.withKind(DoNothing);
7267330f729Sjoerg break;
7277330f729Sjoerg case DecRefAndStopTrackingHard:
7287330f729Sjoerg AE = AE.withKind(StopTracking);
7297330f729Sjoerg break;
7307330f729Sjoerg }
7317330f729Sjoerg }
7327330f729Sjoerg
7337330f729Sjoerg // Handle all use-after-releases.
7347330f729Sjoerg if (V.getKind() == RefVal::Released) {
7357330f729Sjoerg V = V ^ RefVal::ErrorUseAfterRelease;
7367330f729Sjoerg hasErr = V.getKind();
7377330f729Sjoerg return setRefBinding(state, sym, V);
7387330f729Sjoerg }
7397330f729Sjoerg
7407330f729Sjoerg switch (AE.getKind()) {
7417330f729Sjoerg case UnretainedOutParameter:
7427330f729Sjoerg case RetainedOutParameter:
7437330f729Sjoerg case RetainedOutParameterOnZero:
7447330f729Sjoerg case RetainedOutParameterOnNonZero:
7457330f729Sjoerg llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
7467330f729Sjoerg "not have ref state.");
7477330f729Sjoerg
7487330f729Sjoerg case Dealloc: // NB. we only need to add a note in a non-error case.
7497330f729Sjoerg switch (V.getKind()) {
7507330f729Sjoerg default:
7517330f729Sjoerg llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
7527330f729Sjoerg case RefVal::Owned:
7537330f729Sjoerg // The object immediately transitions to the released state.
7547330f729Sjoerg V = V ^ RefVal::Released;
7557330f729Sjoerg V.clearCounts();
7567330f729Sjoerg return setRefBinding(state, sym, V);
7577330f729Sjoerg case RefVal::NotOwned:
7587330f729Sjoerg V = V ^ RefVal::ErrorDeallocNotOwned;
7597330f729Sjoerg hasErr = V.getKind();
7607330f729Sjoerg break;
7617330f729Sjoerg }
7627330f729Sjoerg break;
7637330f729Sjoerg
7647330f729Sjoerg case MayEscape:
7657330f729Sjoerg if (V.getKind() == RefVal::Owned) {
7667330f729Sjoerg V = V ^ RefVal::NotOwned;
7677330f729Sjoerg break;
7687330f729Sjoerg }
7697330f729Sjoerg
7707330f729Sjoerg LLVM_FALLTHROUGH;
7717330f729Sjoerg
7727330f729Sjoerg case DoNothing:
7737330f729Sjoerg return state;
7747330f729Sjoerg
7757330f729Sjoerg case Autorelease:
7767330f729Sjoerg // Update the autorelease counts.
7777330f729Sjoerg V = V.autorelease();
7787330f729Sjoerg break;
7797330f729Sjoerg
7807330f729Sjoerg case StopTracking:
7817330f729Sjoerg case StopTrackingHard:
7827330f729Sjoerg return removeRefBinding(state, sym);
7837330f729Sjoerg
7847330f729Sjoerg case IncRef:
7857330f729Sjoerg switch (V.getKind()) {
7867330f729Sjoerg default:
7877330f729Sjoerg llvm_unreachable("Invalid RefVal state for a retain.");
7887330f729Sjoerg case RefVal::Owned:
7897330f729Sjoerg case RefVal::NotOwned:
7907330f729Sjoerg V = V + 1;
7917330f729Sjoerg break;
7927330f729Sjoerg }
7937330f729Sjoerg break;
7947330f729Sjoerg
7957330f729Sjoerg case DecRef:
7967330f729Sjoerg case DecRefBridgedTransferred:
7977330f729Sjoerg case DecRefAndStopTrackingHard:
7987330f729Sjoerg switch (V.getKind()) {
7997330f729Sjoerg default:
8007330f729Sjoerg // case 'RefVal::Released' handled above.
8017330f729Sjoerg llvm_unreachable("Invalid RefVal state for a release.");
8027330f729Sjoerg
8037330f729Sjoerg case RefVal::Owned:
8047330f729Sjoerg assert(V.getCount() > 0);
8057330f729Sjoerg if (V.getCount() == 1) {
8067330f729Sjoerg if (AE.getKind() == DecRefBridgedTransferred ||
8077330f729Sjoerg V.getIvarAccessHistory() ==
8087330f729Sjoerg RefVal::IvarAccessHistory::AccessedDirectly)
8097330f729Sjoerg V = V ^ RefVal::NotOwned;
8107330f729Sjoerg else
8117330f729Sjoerg V = V ^ RefVal::Released;
8127330f729Sjoerg } else if (AE.getKind() == DecRefAndStopTrackingHard) {
8137330f729Sjoerg return removeRefBinding(state, sym);
8147330f729Sjoerg }
8157330f729Sjoerg
8167330f729Sjoerg V = V - 1;
8177330f729Sjoerg break;
8187330f729Sjoerg
8197330f729Sjoerg case RefVal::NotOwned:
8207330f729Sjoerg if (V.getCount() > 0) {
8217330f729Sjoerg if (AE.getKind() == DecRefAndStopTrackingHard)
8227330f729Sjoerg return removeRefBinding(state, sym);
8237330f729Sjoerg V = V - 1;
8247330f729Sjoerg } else if (V.getIvarAccessHistory() ==
8257330f729Sjoerg RefVal::IvarAccessHistory::AccessedDirectly) {
8267330f729Sjoerg // Assume that the instance variable was holding on the object at
8277330f729Sjoerg // +1, and we just didn't know.
8287330f729Sjoerg if (AE.getKind() == DecRefAndStopTrackingHard)
8297330f729Sjoerg return removeRefBinding(state, sym);
8307330f729Sjoerg V = V.releaseViaIvar() ^ RefVal::Released;
8317330f729Sjoerg } else {
8327330f729Sjoerg V = V ^ RefVal::ErrorReleaseNotOwned;
8337330f729Sjoerg hasErr = V.getKind();
8347330f729Sjoerg }
8357330f729Sjoerg break;
8367330f729Sjoerg }
8377330f729Sjoerg break;
8387330f729Sjoerg }
8397330f729Sjoerg return setRefBinding(state, sym, V);
8407330f729Sjoerg }
8417330f729Sjoerg
8427330f729Sjoerg const RefCountBug &
errorKindToBugKind(RefVal::Kind ErrorKind,SymbolRef Sym) const8437330f729Sjoerg RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
8447330f729Sjoerg SymbolRef Sym) const {
8457330f729Sjoerg switch (ErrorKind) {
8467330f729Sjoerg case RefVal::ErrorUseAfterRelease:
847*e038c9c4Sjoerg return *UseAfterRelease;
8487330f729Sjoerg case RefVal::ErrorReleaseNotOwned:
849*e038c9c4Sjoerg return *ReleaseNotOwned;
8507330f729Sjoerg case RefVal::ErrorDeallocNotOwned:
8517330f729Sjoerg if (Sym->getType()->getPointeeCXXRecordDecl())
852*e038c9c4Sjoerg return *FreeNotOwned;
853*e038c9c4Sjoerg return *DeallocNotOwned;
8547330f729Sjoerg default:
8557330f729Sjoerg llvm_unreachable("Unhandled error.");
8567330f729Sjoerg }
8577330f729Sjoerg }
8587330f729Sjoerg
processNonLeakError(ProgramStateRef St,SourceRange ErrorRange,RefVal::Kind ErrorKind,SymbolRef Sym,CheckerContext & C) const8597330f729Sjoerg void RetainCountChecker::processNonLeakError(ProgramStateRef St,
8607330f729Sjoerg SourceRange ErrorRange,
8617330f729Sjoerg RefVal::Kind ErrorKind,
8627330f729Sjoerg SymbolRef Sym,
8637330f729Sjoerg CheckerContext &C) const {
8647330f729Sjoerg // HACK: Ignore retain-count issues on values accessed through ivars,
8657330f729Sjoerg // because of cases like this:
8667330f729Sjoerg // [_contentView retain];
8677330f729Sjoerg // [_contentView removeFromSuperview];
8687330f729Sjoerg // [self addSubview:_contentView]; // invalidates 'self'
8697330f729Sjoerg // [_contentView release];
8707330f729Sjoerg if (const RefVal *RV = getRefBinding(St, Sym))
8717330f729Sjoerg if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
8727330f729Sjoerg return;
8737330f729Sjoerg
8747330f729Sjoerg ExplodedNode *N = C.generateErrorNode(St);
8757330f729Sjoerg if (!N)
8767330f729Sjoerg return;
8777330f729Sjoerg
8787330f729Sjoerg auto report = std::make_unique<RefCountReport>(
8797330f729Sjoerg errorKindToBugKind(ErrorKind, Sym),
8807330f729Sjoerg C.getASTContext().getLangOpts(), N, Sym);
8817330f729Sjoerg report->addRange(ErrorRange);
8827330f729Sjoerg C.emitReport(std::move(report));
8837330f729Sjoerg }
8847330f729Sjoerg
8857330f729Sjoerg //===----------------------------------------------------------------------===//
8867330f729Sjoerg // Handle the return values of retain-count-related functions.
8877330f729Sjoerg //===----------------------------------------------------------------------===//
8887330f729Sjoerg
evalCall(const CallEvent & Call,CheckerContext & C) const8897330f729Sjoerg bool RetainCountChecker::evalCall(const CallEvent &Call,
8907330f729Sjoerg CheckerContext &C) const {
8917330f729Sjoerg ProgramStateRef state = C.getState();
8927330f729Sjoerg const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
8937330f729Sjoerg if (!FD)
8947330f729Sjoerg return false;
8957330f729Sjoerg
8967330f729Sjoerg const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
8977330f729Sjoerg if (!CE)
8987330f729Sjoerg return false;
8997330f729Sjoerg
9007330f729Sjoerg RetainSummaryManager &SmrMgr = getSummaryManager(C);
9017330f729Sjoerg QualType ResultTy = Call.getResultType();
9027330f729Sjoerg
9037330f729Sjoerg // See if the function has 'rc_ownership_trusted_implementation'
9047330f729Sjoerg // annotate attribute. If it does, we will not inline it.
9057330f729Sjoerg bool hasTrustedImplementationAnnotation = false;
9067330f729Sjoerg
9077330f729Sjoerg const LocationContext *LCtx = C.getLocationContext();
9087330f729Sjoerg
9097330f729Sjoerg using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
9107330f729Sjoerg Optional<BehaviorSummary> BSmr =
9117330f729Sjoerg SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
9127330f729Sjoerg
9137330f729Sjoerg // See if it's one of the specific functions we know how to eval.
9147330f729Sjoerg if (!BSmr)
9157330f729Sjoerg return false;
9167330f729Sjoerg
9177330f729Sjoerg // Bind the return value.
9187330f729Sjoerg if (BSmr == BehaviorSummary::Identity ||
9197330f729Sjoerg BSmr == BehaviorSummary::IdentityOrZero ||
9207330f729Sjoerg BSmr == BehaviorSummary::IdentityThis) {
9217330f729Sjoerg
9227330f729Sjoerg const Expr *BindReturnTo =
9237330f729Sjoerg (BSmr == BehaviorSummary::IdentityThis)
9247330f729Sjoerg ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
9257330f729Sjoerg : CE->getArg(0);
9267330f729Sjoerg SVal RetVal = state->getSVal(BindReturnTo, LCtx);
9277330f729Sjoerg
9287330f729Sjoerg // If the receiver is unknown or the function has
9297330f729Sjoerg // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
9307330f729Sjoerg // return value.
9317330f729Sjoerg // FIXME: this branch is very strange.
9327330f729Sjoerg if (RetVal.isUnknown() ||
9337330f729Sjoerg (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
9347330f729Sjoerg SValBuilder &SVB = C.getSValBuilder();
9357330f729Sjoerg RetVal =
9367330f729Sjoerg SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
9377330f729Sjoerg }
9387330f729Sjoerg
9397330f729Sjoerg // Bind the value.
9407330f729Sjoerg state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
9417330f729Sjoerg
9427330f729Sjoerg if (BSmr == BehaviorSummary::IdentityOrZero) {
9437330f729Sjoerg // Add a branch where the output is zero.
9447330f729Sjoerg ProgramStateRef NullOutputState = C.getState();
9457330f729Sjoerg
9467330f729Sjoerg // Assume that output is zero on the other branch.
9477330f729Sjoerg NullOutputState = NullOutputState->BindExpr(
9487330f729Sjoerg CE, LCtx, C.getSValBuilder().makeNull(), /*Invalidate=*/false);
949*e038c9c4Sjoerg C.addTransition(NullOutputState, &getCastFailTag());
9507330f729Sjoerg
9517330f729Sjoerg // And on the original branch assume that both input and
9527330f729Sjoerg // output are non-zero.
9537330f729Sjoerg if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
9547330f729Sjoerg state = state->assume(*L, /*assumption=*/true);
9557330f729Sjoerg
9567330f729Sjoerg }
9577330f729Sjoerg }
9587330f729Sjoerg
9597330f729Sjoerg C.addTransition(state);
9607330f729Sjoerg return true;
9617330f729Sjoerg }
9627330f729Sjoerg
processReturn(const ReturnStmt * S,CheckerContext & C) const9637330f729Sjoerg ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
9647330f729Sjoerg CheckerContext &C) const {
9657330f729Sjoerg ExplodedNode *Pred = C.getPredecessor();
9667330f729Sjoerg
9677330f729Sjoerg // Only adjust the reference count if this is the top-level call frame,
9687330f729Sjoerg // and not the result of inlining. In the future, we should do
9697330f729Sjoerg // better checking even for inlined calls, and see if they match
9707330f729Sjoerg // with their expected semantics (e.g., the method should return a retained
9717330f729Sjoerg // object, etc.).
9727330f729Sjoerg if (!C.inTopFrame())
9737330f729Sjoerg return Pred;
9747330f729Sjoerg
9757330f729Sjoerg if (!S)
9767330f729Sjoerg return Pred;
9777330f729Sjoerg
9787330f729Sjoerg const Expr *RetE = S->getRetValue();
9797330f729Sjoerg if (!RetE)
9807330f729Sjoerg return Pred;
9817330f729Sjoerg
9827330f729Sjoerg ProgramStateRef state = C.getState();
9837330f729Sjoerg // We need to dig down to the symbolic base here because various
9847330f729Sjoerg // custom allocators do sometimes return the symbol with an offset.
9857330f729Sjoerg SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext())
9867330f729Sjoerg .getAsLocSymbol(/*IncludeBaseRegions=*/true);
9877330f729Sjoerg if (!Sym)
9887330f729Sjoerg return Pred;
9897330f729Sjoerg
9907330f729Sjoerg // Get the reference count binding (if any).
9917330f729Sjoerg const RefVal *T = getRefBinding(state, Sym);
9927330f729Sjoerg if (!T)
9937330f729Sjoerg return Pred;
9947330f729Sjoerg
9957330f729Sjoerg // Change the reference count.
9967330f729Sjoerg RefVal X = *T;
9977330f729Sjoerg
9987330f729Sjoerg switch (X.getKind()) {
9997330f729Sjoerg case RefVal::Owned: {
10007330f729Sjoerg unsigned cnt = X.getCount();
10017330f729Sjoerg assert(cnt > 0);
10027330f729Sjoerg X.setCount(cnt - 1);
10037330f729Sjoerg X = X ^ RefVal::ReturnedOwned;
10047330f729Sjoerg break;
10057330f729Sjoerg }
10067330f729Sjoerg
10077330f729Sjoerg case RefVal::NotOwned: {
10087330f729Sjoerg unsigned cnt = X.getCount();
10097330f729Sjoerg if (cnt) {
10107330f729Sjoerg X.setCount(cnt - 1);
10117330f729Sjoerg X = X ^ RefVal::ReturnedOwned;
10127330f729Sjoerg } else {
10137330f729Sjoerg X = X ^ RefVal::ReturnedNotOwned;
10147330f729Sjoerg }
10157330f729Sjoerg break;
10167330f729Sjoerg }
10177330f729Sjoerg
10187330f729Sjoerg default:
10197330f729Sjoerg return Pred;
10207330f729Sjoerg }
10217330f729Sjoerg
10227330f729Sjoerg // Update the binding.
10237330f729Sjoerg state = setRefBinding(state, Sym, X);
10247330f729Sjoerg Pred = C.addTransition(state);
10257330f729Sjoerg
10267330f729Sjoerg // At this point we have updated the state properly.
10277330f729Sjoerg // Everything after this is merely checking to see if the return value has
10287330f729Sjoerg // been over- or under-retained.
10297330f729Sjoerg
10307330f729Sjoerg // Did we cache out?
10317330f729Sjoerg if (!Pred)
10327330f729Sjoerg return nullptr;
10337330f729Sjoerg
10347330f729Sjoerg // Update the autorelease counts.
10357330f729Sjoerg static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease");
10367330f729Sjoerg state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S);
10377330f729Sjoerg
10387330f729Sjoerg // Have we generated a sink node?
10397330f729Sjoerg if (!state)
10407330f729Sjoerg return nullptr;
10417330f729Sjoerg
10427330f729Sjoerg // Get the updated binding.
10437330f729Sjoerg T = getRefBinding(state, Sym);
10447330f729Sjoerg assert(T);
10457330f729Sjoerg X = *T;
10467330f729Sjoerg
10477330f729Sjoerg // Consult the summary of the enclosing method.
10487330f729Sjoerg RetainSummaryManager &Summaries = getSummaryManager(C);
10497330f729Sjoerg const Decl *CD = &Pred->getCodeDecl();
10507330f729Sjoerg RetEffect RE = RetEffect::MakeNoRet();
10517330f729Sjoerg
10527330f729Sjoerg // FIXME: What is the convention for blocks? Is there one?
10537330f729Sjoerg if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
10547330f729Sjoerg const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD));
10557330f729Sjoerg RE = Summ->getRetEffect();
10567330f729Sjoerg } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
10577330f729Sjoerg if (!isa<CXXMethodDecl>(FD)) {
10587330f729Sjoerg const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD));
10597330f729Sjoerg RE = Summ->getRetEffect();
10607330f729Sjoerg }
10617330f729Sjoerg }
10627330f729Sjoerg
10637330f729Sjoerg return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
10647330f729Sjoerg }
10657330f729Sjoerg
checkReturnWithRetEffect(const ReturnStmt * S,CheckerContext & C,ExplodedNode * Pred,RetEffect RE,RefVal X,SymbolRef Sym,ProgramStateRef state) const10667330f729Sjoerg ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
10677330f729Sjoerg CheckerContext &C,
10687330f729Sjoerg ExplodedNode *Pred,
10697330f729Sjoerg RetEffect RE, RefVal X,
10707330f729Sjoerg SymbolRef Sym,
10717330f729Sjoerg ProgramStateRef state) const {
10727330f729Sjoerg // HACK: Ignore retain-count issues on values accessed through ivars,
10737330f729Sjoerg // because of cases like this:
10747330f729Sjoerg // [_contentView retain];
10757330f729Sjoerg // [_contentView removeFromSuperview];
10767330f729Sjoerg // [self addSubview:_contentView]; // invalidates 'self'
10777330f729Sjoerg // [_contentView release];
10787330f729Sjoerg if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
10797330f729Sjoerg return Pred;
10807330f729Sjoerg
10817330f729Sjoerg // Any leaks or other errors?
10827330f729Sjoerg if (X.isReturnedOwned() && X.getCount() == 0) {
10837330f729Sjoerg if (RE.getKind() != RetEffect::NoRet) {
10847330f729Sjoerg if (!RE.isOwned()) {
10857330f729Sjoerg
10867330f729Sjoerg // The returning type is a CF, we expect the enclosing method should
10877330f729Sjoerg // return ownership.
10887330f729Sjoerg X = X ^ RefVal::ErrorLeakReturned;
10897330f729Sjoerg
10907330f729Sjoerg // Generate an error node.
10917330f729Sjoerg state = setRefBinding(state, Sym, X);
10927330f729Sjoerg
10937330f729Sjoerg static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak");
10947330f729Sjoerg ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
10957330f729Sjoerg if (N) {
10967330f729Sjoerg const LangOptions &LOpts = C.getASTContext().getLangOpts();
10977330f729Sjoerg auto R =
1098*e038c9c4Sjoerg std::make_unique<RefLeakReport>(*LeakAtReturn, LOpts, N, Sym, C);
10997330f729Sjoerg C.emitReport(std::move(R));
11007330f729Sjoerg }
11017330f729Sjoerg return N;
11027330f729Sjoerg }
11037330f729Sjoerg }
11047330f729Sjoerg } else if (X.isReturnedNotOwned()) {
11057330f729Sjoerg if (RE.isOwned()) {
11067330f729Sjoerg if (X.getIvarAccessHistory() ==
11077330f729Sjoerg RefVal::IvarAccessHistory::AccessedDirectly) {
11087330f729Sjoerg // Assume the method was trying to transfer a +1 reference from a
11097330f729Sjoerg // strong ivar to the caller.
11107330f729Sjoerg state = setRefBinding(state, Sym,
11117330f729Sjoerg X.releaseViaIvar() ^ RefVal::ReturnedOwned);
11127330f729Sjoerg } else {
11137330f729Sjoerg // Trying to return a not owned object to a caller expecting an
11147330f729Sjoerg // owned object.
11157330f729Sjoerg state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
11167330f729Sjoerg
11177330f729Sjoerg static CheckerProgramPointTag
11187330f729Sjoerg ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned");
11197330f729Sjoerg
11207330f729Sjoerg ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
11217330f729Sjoerg if (N) {
11227330f729Sjoerg auto R = std::make_unique<RefCountReport>(
1123*e038c9c4Sjoerg *ReturnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
11247330f729Sjoerg C.emitReport(std::move(R));
11257330f729Sjoerg }
11267330f729Sjoerg return N;
11277330f729Sjoerg }
11287330f729Sjoerg }
11297330f729Sjoerg }
11307330f729Sjoerg return Pred;
11317330f729Sjoerg }
11327330f729Sjoerg
11337330f729Sjoerg //===----------------------------------------------------------------------===//
11347330f729Sjoerg // Check various ways a symbol can be invalidated.
11357330f729Sjoerg //===----------------------------------------------------------------------===//
11367330f729Sjoerg
checkBind(SVal loc,SVal val,const Stmt * S,CheckerContext & C) const11377330f729Sjoerg void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
11387330f729Sjoerg CheckerContext &C) const {
11397330f729Sjoerg ProgramStateRef state = C.getState();
11407330f729Sjoerg const MemRegion *MR = loc.getAsRegion();
11417330f729Sjoerg
11427330f729Sjoerg // Find all symbols referenced by 'val' that we are tracking
11437330f729Sjoerg // and stop tracking them.
11447330f729Sjoerg if (MR && shouldEscapeRegion(MR)) {
11457330f729Sjoerg state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
11467330f729Sjoerg C.addTransition(state);
11477330f729Sjoerg }
11487330f729Sjoerg }
11497330f729Sjoerg
evalAssume(ProgramStateRef state,SVal Cond,bool Assumption) const11507330f729Sjoerg ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
11517330f729Sjoerg SVal Cond,
11527330f729Sjoerg bool Assumption) const {
11537330f729Sjoerg // FIXME: We may add to the interface of evalAssume the list of symbols
11547330f729Sjoerg // whose assumptions have changed. For now we just iterate through the
11557330f729Sjoerg // bindings and check if any of the tracked symbols are NULL. This isn't
11567330f729Sjoerg // too bad since the number of symbols we will track in practice are
11577330f729Sjoerg // probably small and evalAssume is only called at branches and a few
11587330f729Sjoerg // other places.
11597330f729Sjoerg RefBindingsTy B = state->get<RefBindings>();
11607330f729Sjoerg
11617330f729Sjoerg if (B.isEmpty())
11627330f729Sjoerg return state;
11637330f729Sjoerg
11647330f729Sjoerg bool changed = false;
11657330f729Sjoerg RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
11667330f729Sjoerg ConstraintManager &CMgr = state->getConstraintManager();
11677330f729Sjoerg
11687330f729Sjoerg for (auto &I : B) {
11697330f729Sjoerg // Check if the symbol is null stop tracking the symbol.
11707330f729Sjoerg ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
11717330f729Sjoerg if (AllocFailed.isConstrainedTrue()) {
11727330f729Sjoerg changed = true;
11737330f729Sjoerg B = RefBFactory.remove(B, I.first);
11747330f729Sjoerg }
11757330f729Sjoerg }
11767330f729Sjoerg
11777330f729Sjoerg if (changed)
11787330f729Sjoerg state = state->set<RefBindings>(B);
11797330f729Sjoerg
11807330f729Sjoerg return state;
11817330f729Sjoerg }
11827330f729Sjoerg
checkRegionChanges(ProgramStateRef state,const InvalidatedSymbols * invalidated,ArrayRef<const MemRegion * > ExplicitRegions,ArrayRef<const MemRegion * > Regions,const LocationContext * LCtx,const CallEvent * Call) const11837330f729Sjoerg ProgramStateRef RetainCountChecker::checkRegionChanges(
11847330f729Sjoerg ProgramStateRef state, const InvalidatedSymbols *invalidated,
11857330f729Sjoerg ArrayRef<const MemRegion *> ExplicitRegions,
11867330f729Sjoerg ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
11877330f729Sjoerg const CallEvent *Call) const {
11887330f729Sjoerg if (!invalidated)
11897330f729Sjoerg return state;
11907330f729Sjoerg
11917330f729Sjoerg llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
11927330f729Sjoerg
11937330f729Sjoerg for (const MemRegion *I : ExplicitRegions)
11947330f729Sjoerg if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
11957330f729Sjoerg WhitelistedSymbols.insert(SR->getSymbol());
11967330f729Sjoerg
11977330f729Sjoerg for (SymbolRef sym : *invalidated) {
11987330f729Sjoerg if (WhitelistedSymbols.count(sym))
11997330f729Sjoerg continue;
12007330f729Sjoerg // Remove any existing reference-count binding.
12017330f729Sjoerg state = removeRefBinding(state, sym);
12027330f729Sjoerg }
12037330f729Sjoerg return state;
12047330f729Sjoerg }
12057330f729Sjoerg
12067330f729Sjoerg ProgramStateRef
handleAutoreleaseCounts(ProgramStateRef state,ExplodedNode * Pred,const ProgramPointTag * Tag,CheckerContext & Ctx,SymbolRef Sym,RefVal V,const ReturnStmt * S) const12077330f729Sjoerg RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
12087330f729Sjoerg ExplodedNode *Pred,
12097330f729Sjoerg const ProgramPointTag *Tag,
12107330f729Sjoerg CheckerContext &Ctx,
12117330f729Sjoerg SymbolRef Sym,
12127330f729Sjoerg RefVal V,
12137330f729Sjoerg const ReturnStmt *S) const {
12147330f729Sjoerg unsigned ACnt = V.getAutoreleaseCount();
12157330f729Sjoerg
12167330f729Sjoerg // No autorelease counts? Nothing to be done.
12177330f729Sjoerg if (!ACnt)
12187330f729Sjoerg return state;
12197330f729Sjoerg
12207330f729Sjoerg unsigned Cnt = V.getCount();
12217330f729Sjoerg
12227330f729Sjoerg // FIXME: Handle sending 'autorelease' to already released object.
12237330f729Sjoerg
12247330f729Sjoerg if (V.getKind() == RefVal::ReturnedOwned)
12257330f729Sjoerg ++Cnt;
12267330f729Sjoerg
12277330f729Sjoerg // If we would over-release here, but we know the value came from an ivar,
12287330f729Sjoerg // assume it was a strong ivar that's just been relinquished.
12297330f729Sjoerg if (ACnt > Cnt &&
12307330f729Sjoerg V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
12317330f729Sjoerg V = V.releaseViaIvar();
12327330f729Sjoerg --ACnt;
12337330f729Sjoerg }
12347330f729Sjoerg
12357330f729Sjoerg if (ACnt <= Cnt) {
12367330f729Sjoerg if (ACnt == Cnt) {
12377330f729Sjoerg V.clearCounts();
12387330f729Sjoerg if (V.getKind() == RefVal::ReturnedOwned) {
12397330f729Sjoerg V = V ^ RefVal::ReturnedNotOwned;
12407330f729Sjoerg } else {
12417330f729Sjoerg V = V ^ RefVal::NotOwned;
12427330f729Sjoerg }
12437330f729Sjoerg } else {
12447330f729Sjoerg V.setCount(V.getCount() - ACnt);
12457330f729Sjoerg V.setAutoreleaseCount(0);
12467330f729Sjoerg }
12477330f729Sjoerg return setRefBinding(state, Sym, V);
12487330f729Sjoerg }
12497330f729Sjoerg
12507330f729Sjoerg // HACK: Ignore retain-count issues on values accessed through ivars,
12517330f729Sjoerg // because of cases like this:
12527330f729Sjoerg // [_contentView retain];
12537330f729Sjoerg // [_contentView removeFromSuperview];
12547330f729Sjoerg // [self addSubview:_contentView]; // invalidates 'self'
12557330f729Sjoerg // [_contentView release];
12567330f729Sjoerg if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
12577330f729Sjoerg return state;
12587330f729Sjoerg
12597330f729Sjoerg // Woah! More autorelease counts then retain counts left.
12607330f729Sjoerg // Emit hard error.
12617330f729Sjoerg V = V ^ RefVal::ErrorOverAutorelease;
12627330f729Sjoerg state = setRefBinding(state, Sym, V);
12637330f729Sjoerg
12647330f729Sjoerg ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
12657330f729Sjoerg if (N) {
12667330f729Sjoerg SmallString<128> sbuf;
12677330f729Sjoerg llvm::raw_svector_ostream os(sbuf);
12687330f729Sjoerg os << "Object was autoreleased ";
12697330f729Sjoerg if (V.getAutoreleaseCount() > 1)
12707330f729Sjoerg os << V.getAutoreleaseCount() << " times but the object ";
12717330f729Sjoerg else
12727330f729Sjoerg os << "but ";
12737330f729Sjoerg os << "has a +" << V.getCount() << " retain count";
12747330f729Sjoerg
12757330f729Sjoerg const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
1276*e038c9c4Sjoerg auto R = std::make_unique<RefCountReport>(*OverAutorelease, LOpts, N, Sym,
12777330f729Sjoerg os.str());
12787330f729Sjoerg Ctx.emitReport(std::move(R));
12797330f729Sjoerg }
12807330f729Sjoerg
12817330f729Sjoerg return nullptr;
12827330f729Sjoerg }
12837330f729Sjoerg
12847330f729Sjoerg ProgramStateRef
handleSymbolDeath(ProgramStateRef state,SymbolRef sid,RefVal V,SmallVectorImpl<SymbolRef> & Leaked) const12857330f729Sjoerg RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
12867330f729Sjoerg SymbolRef sid, RefVal V,
12877330f729Sjoerg SmallVectorImpl<SymbolRef> &Leaked) const {
12887330f729Sjoerg bool hasLeak;
12897330f729Sjoerg
12907330f729Sjoerg // HACK: Ignore retain-count issues on values accessed through ivars,
12917330f729Sjoerg // because of cases like this:
12927330f729Sjoerg // [_contentView retain];
12937330f729Sjoerg // [_contentView removeFromSuperview];
12947330f729Sjoerg // [self addSubview:_contentView]; // invalidates 'self'
12957330f729Sjoerg // [_contentView release];
12967330f729Sjoerg if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
12977330f729Sjoerg hasLeak = false;
12987330f729Sjoerg else if (V.isOwned())
12997330f729Sjoerg hasLeak = true;
13007330f729Sjoerg else if (V.isNotOwned() || V.isReturnedOwned())
13017330f729Sjoerg hasLeak = (V.getCount() > 0);
13027330f729Sjoerg else
13037330f729Sjoerg hasLeak = false;
13047330f729Sjoerg
13057330f729Sjoerg if (!hasLeak)
13067330f729Sjoerg return removeRefBinding(state, sid);
13077330f729Sjoerg
13087330f729Sjoerg Leaked.push_back(sid);
13097330f729Sjoerg return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
13107330f729Sjoerg }
13117330f729Sjoerg
13127330f729Sjoerg ExplodedNode *
processLeaks(ProgramStateRef state,SmallVectorImpl<SymbolRef> & Leaked,CheckerContext & Ctx,ExplodedNode * Pred) const13137330f729Sjoerg RetainCountChecker::processLeaks(ProgramStateRef state,
13147330f729Sjoerg SmallVectorImpl<SymbolRef> &Leaked,
13157330f729Sjoerg CheckerContext &Ctx,
13167330f729Sjoerg ExplodedNode *Pred) const {
13177330f729Sjoerg // Generate an intermediate node representing the leak point.
13187330f729Sjoerg ExplodedNode *N = Ctx.addTransition(state, Pred);
13197330f729Sjoerg const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
13207330f729Sjoerg
13217330f729Sjoerg if (N) {
13227330f729Sjoerg for (SymbolRef L : Leaked) {
1323*e038c9c4Sjoerg const RefCountBug &BT = Pred ? *LeakWithinFunction : *LeakAtReturn;
13247330f729Sjoerg Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
13257330f729Sjoerg }
13267330f729Sjoerg }
13277330f729Sjoerg
13287330f729Sjoerg return N;
13297330f729Sjoerg }
13307330f729Sjoerg
checkBeginFunction(CheckerContext & Ctx) const13317330f729Sjoerg void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
13327330f729Sjoerg if (!Ctx.inTopFrame())
13337330f729Sjoerg return;
13347330f729Sjoerg
13357330f729Sjoerg RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
13367330f729Sjoerg const LocationContext *LCtx = Ctx.getLocationContext();
13377330f729Sjoerg const Decl *D = LCtx->getDecl();
13387330f729Sjoerg Optional<AnyCall> C = AnyCall::forDecl(D);
13397330f729Sjoerg
13407330f729Sjoerg if (!C || SmrMgr.isTrustedReferenceCountImplementation(D))
13417330f729Sjoerg return;
13427330f729Sjoerg
13437330f729Sjoerg ProgramStateRef state = Ctx.getState();
13447330f729Sjoerg const RetainSummary *FunctionSummary = SmrMgr.getSummary(*C);
13457330f729Sjoerg ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
13467330f729Sjoerg
13477330f729Sjoerg for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) {
13487330f729Sjoerg const ParmVarDecl *Param = C->parameters()[idx];
13497330f729Sjoerg SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
13507330f729Sjoerg
13517330f729Sjoerg QualType Ty = Param->getType();
13527330f729Sjoerg const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
13537330f729Sjoerg if (AE) {
13547330f729Sjoerg ObjKind K = AE->getObjKind();
13557330f729Sjoerg if (K == ObjKind::Generalized || K == ObjKind::OS ||
13567330f729Sjoerg (TrackNSCFStartParam && (K == ObjKind::ObjC || K == ObjKind::CF))) {
13577330f729Sjoerg RefVal NewVal = AE->getKind() == DecRef ? RefVal::makeOwned(K, Ty)
13587330f729Sjoerg : RefVal::makeNotOwned(K, Ty);
13597330f729Sjoerg state = setRefBinding(state, Sym, NewVal);
13607330f729Sjoerg }
13617330f729Sjoerg }
13627330f729Sjoerg }
13637330f729Sjoerg
13647330f729Sjoerg Ctx.addTransition(state);
13657330f729Sjoerg }
13667330f729Sjoerg
checkEndFunction(const ReturnStmt * RS,CheckerContext & Ctx) const13677330f729Sjoerg void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
13687330f729Sjoerg CheckerContext &Ctx) const {
13697330f729Sjoerg ExplodedNode *Pred = processReturn(RS, Ctx);
13707330f729Sjoerg
13717330f729Sjoerg // Created state cached out.
13727330f729Sjoerg if (!Pred) {
13737330f729Sjoerg return;
13747330f729Sjoerg }
13757330f729Sjoerg
13767330f729Sjoerg ProgramStateRef state = Pred->getState();
13777330f729Sjoerg RefBindingsTy B = state->get<RefBindings>();
13787330f729Sjoerg
13797330f729Sjoerg // Don't process anything within synthesized bodies.
13807330f729Sjoerg const LocationContext *LCtx = Pred->getLocationContext();
13817330f729Sjoerg if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
13827330f729Sjoerg assert(!LCtx->inTopFrame());
13837330f729Sjoerg return;
13847330f729Sjoerg }
13857330f729Sjoerg
13867330f729Sjoerg for (auto &I : B) {
13877330f729Sjoerg state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx,
13887330f729Sjoerg I.first, I.second);
13897330f729Sjoerg if (!state)
13907330f729Sjoerg return;
13917330f729Sjoerg }
13927330f729Sjoerg
13937330f729Sjoerg // If the current LocationContext has a parent, don't check for leaks.
13947330f729Sjoerg // We will do that later.
13957330f729Sjoerg // FIXME: we should instead check for imbalances of the retain/releases,
13967330f729Sjoerg // and suggest annotations.
13977330f729Sjoerg if (LCtx->getParent())
13987330f729Sjoerg return;
13997330f729Sjoerg
14007330f729Sjoerg B = state->get<RefBindings>();
14017330f729Sjoerg SmallVector<SymbolRef, 10> Leaked;
14027330f729Sjoerg
14037330f729Sjoerg for (auto &I : B)
14047330f729Sjoerg state = handleSymbolDeath(state, I.first, I.second, Leaked);
14057330f729Sjoerg
14067330f729Sjoerg processLeaks(state, Leaked, Ctx, Pred);
14077330f729Sjoerg }
14087330f729Sjoerg
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const14097330f729Sjoerg void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
14107330f729Sjoerg CheckerContext &C) const {
14117330f729Sjoerg ExplodedNode *Pred = C.getPredecessor();
14127330f729Sjoerg
14137330f729Sjoerg ProgramStateRef state = C.getState();
14147330f729Sjoerg SmallVector<SymbolRef, 10> Leaked;
14157330f729Sjoerg
14167330f729Sjoerg // Update counts from autorelease pools
14177330f729Sjoerg for (const auto &I: state->get<RefBindings>()) {
14187330f729Sjoerg SymbolRef Sym = I.first;
14197330f729Sjoerg if (SymReaper.isDead(Sym)) {
14207330f729Sjoerg static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease");
14217330f729Sjoerg const RefVal &V = I.second;
14227330f729Sjoerg state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V);
14237330f729Sjoerg if (!state)
14247330f729Sjoerg return;
14257330f729Sjoerg
14267330f729Sjoerg // Fetch the new reference count from the state, and use it to handle
14277330f729Sjoerg // this symbol.
14287330f729Sjoerg state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
14297330f729Sjoerg }
14307330f729Sjoerg }
14317330f729Sjoerg
14327330f729Sjoerg if (Leaked.empty()) {
14337330f729Sjoerg C.addTransition(state);
14347330f729Sjoerg return;
14357330f729Sjoerg }
14367330f729Sjoerg
14377330f729Sjoerg Pred = processLeaks(state, Leaked, C, Pred);
14387330f729Sjoerg
14397330f729Sjoerg // Did we cache out?
14407330f729Sjoerg if (!Pred)
14417330f729Sjoerg return;
14427330f729Sjoerg
14437330f729Sjoerg // Now generate a new node that nukes the old bindings.
14447330f729Sjoerg // The only bindings left at this point are the leaked symbols.
14457330f729Sjoerg RefBindingsTy::Factory &F = state->get_context<RefBindings>();
14467330f729Sjoerg RefBindingsTy B = state->get<RefBindings>();
14477330f729Sjoerg
14487330f729Sjoerg for (SymbolRef L : Leaked)
14497330f729Sjoerg B = F.remove(B, L);
14507330f729Sjoerg
14517330f729Sjoerg state = state->set<RefBindings>(B);
14527330f729Sjoerg C.addTransition(state, Pred);
14537330f729Sjoerg }
14547330f729Sjoerg
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const14557330f729Sjoerg void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
14567330f729Sjoerg const char *NL, const char *Sep) const {
14577330f729Sjoerg
14587330f729Sjoerg RefBindingsTy B = State->get<RefBindings>();
14597330f729Sjoerg
14607330f729Sjoerg if (B.isEmpty())
14617330f729Sjoerg return;
14627330f729Sjoerg
14637330f729Sjoerg Out << Sep << NL;
14647330f729Sjoerg
14657330f729Sjoerg for (auto &I : B) {
14667330f729Sjoerg Out << I.first << " : ";
14677330f729Sjoerg I.second.print(Out);
14687330f729Sjoerg Out << NL;
14697330f729Sjoerg }
14707330f729Sjoerg }
14717330f729Sjoerg
14727330f729Sjoerg //===----------------------------------------------------------------------===//
14737330f729Sjoerg // Checker registration.
14747330f729Sjoerg //===----------------------------------------------------------------------===//
14757330f729Sjoerg
1476*e038c9c4Sjoerg std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::DeallocSentTag;
1477*e038c9c4Sjoerg std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::CastFailTag;
1478*e038c9c4Sjoerg
registerRetainCountBase(CheckerManager & Mgr)14797330f729Sjoerg void ento::registerRetainCountBase(CheckerManager &Mgr) {
1480*e038c9c4Sjoerg auto *Chk = Mgr.registerChecker<RetainCountChecker>();
1481*e038c9c4Sjoerg Chk->DeallocSentTag =
1482*e038c9c4Sjoerg std::make_unique<CheckerProgramPointTag>(Chk, "DeallocSent");
1483*e038c9c4Sjoerg Chk->CastFailTag =
1484*e038c9c4Sjoerg std::make_unique<CheckerProgramPointTag>(Chk, "DynamicCastFail");
14857330f729Sjoerg }
14867330f729Sjoerg
shouldRegisterRetainCountBase(const CheckerManager & mgr)1487*e038c9c4Sjoerg bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) {
14887330f729Sjoerg return true;
14897330f729Sjoerg }
registerRetainCountChecker(CheckerManager & Mgr)14907330f729Sjoerg void ento::registerRetainCountChecker(CheckerManager &Mgr) {
14917330f729Sjoerg auto *Chk = Mgr.getChecker<RetainCountChecker>();
14927330f729Sjoerg Chk->TrackObjCAndCFObjects = true;
1493*e038c9c4Sjoerg Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
1494*e038c9c4Sjoerg Mgr.getCurrentCheckerName(), "TrackNSCFStartParam");
1495*e038c9c4Sjoerg
1496*e038c9c4Sjoerg #define INIT_BUGTYPE(KIND) \
1497*e038c9c4Sjoerg Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \
1498*e038c9c4Sjoerg RefCountBug::KIND);
1499*e038c9c4Sjoerg // TODO: Ideally, we should have a checker for each of these bug types.
1500*e038c9c4Sjoerg INIT_BUGTYPE(UseAfterRelease)
1501*e038c9c4Sjoerg INIT_BUGTYPE(ReleaseNotOwned)
1502*e038c9c4Sjoerg INIT_BUGTYPE(DeallocNotOwned)
1503*e038c9c4Sjoerg INIT_BUGTYPE(FreeNotOwned)
1504*e038c9c4Sjoerg INIT_BUGTYPE(OverAutorelease)
1505*e038c9c4Sjoerg INIT_BUGTYPE(ReturnNotOwnedForOwned)
1506*e038c9c4Sjoerg INIT_BUGTYPE(LeakWithinFunction)
1507*e038c9c4Sjoerg INIT_BUGTYPE(LeakAtReturn)
1508*e038c9c4Sjoerg #undef INIT_BUGTYPE
15097330f729Sjoerg }
15107330f729Sjoerg
shouldRegisterRetainCountChecker(const CheckerManager & mgr)1511*e038c9c4Sjoerg bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) {
15127330f729Sjoerg return true;
15137330f729Sjoerg }
15147330f729Sjoerg
registerOSObjectRetainCountChecker(CheckerManager & Mgr)15157330f729Sjoerg void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
15167330f729Sjoerg auto *Chk = Mgr.getChecker<RetainCountChecker>();
15177330f729Sjoerg Chk->TrackOSObjects = true;
1518*e038c9c4Sjoerg
1519*e038c9c4Sjoerg // FIXME: We want bug reports to always have the same checker name associated
1520*e038c9c4Sjoerg // with them, yet here, if RetainCountChecker is disabled but
1521*e038c9c4Sjoerg // OSObjectRetainCountChecker is enabled, the checker names will be different.
1522*e038c9c4Sjoerg // This hack will make it so that the checker name depends on which checker is
1523*e038c9c4Sjoerg // enabled rather than on the registration order.
1524*e038c9c4Sjoerg // For the most part, we want **non-hidden checkers** to be associated with
1525*e038c9c4Sjoerg // diagnostics, and **hidden checker options** with the fine-tuning of
1526*e038c9c4Sjoerg // modeling. Following this logic, OSObjectRetainCountChecker should be the
1527*e038c9c4Sjoerg // latter, but we can't just remove it for backward compatibility reasons.
1528*e038c9c4Sjoerg #define LAZY_INIT_BUGTYPE(KIND) \
1529*e038c9c4Sjoerg if (!Chk->KIND) \
1530*e038c9c4Sjoerg Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \
1531*e038c9c4Sjoerg RefCountBug::KIND);
1532*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(UseAfterRelease)
1533*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(ReleaseNotOwned)
1534*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(DeallocNotOwned)
1535*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(FreeNotOwned)
1536*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(OverAutorelease)
1537*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(ReturnNotOwnedForOwned)
1538*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(LeakWithinFunction)
1539*e038c9c4Sjoerg LAZY_INIT_BUGTYPE(LeakAtReturn)
1540*e038c9c4Sjoerg #undef LAZY_INIT_BUGTYPE
15417330f729Sjoerg }
15427330f729Sjoerg
shouldRegisterOSObjectRetainCountChecker(const CheckerManager & mgr)1543*e038c9c4Sjoerg bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) {
15447330f729Sjoerg return true;
15457330f729Sjoerg }
1546