brintos

brintos / llvm-project-archived public Read only

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