Skip to content
CFRefCount.cpp 83.4 KiB
Newer Older
Ted Kremenek's avatar
Ted Kremenek committed
  
  // Create the "copy" selector.  
  addNSObjectMethSummary(GetNullarySelector("copy", Ctx), Summ);  

Ted Kremenek's avatar
Ted Kremenek committed
  addNSObjectMethSummary(GetNullarySelector("mutableCopy", Ctx), Summ);
  // Create the "retain" selector.
  E = RetEffect::MakeReceiverAlias();
  Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : IncRef);
Ted Kremenek's avatar
Ted Kremenek committed
  addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
  
  // Create the "release" selector.
  Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef);
Ted Kremenek's avatar
Ted Kremenek committed
  addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
Ted Kremenek's avatar
Ted Kremenek committed
  
  // Create the "drain" selector.
  Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef);
Ted Kremenek's avatar
Ted Kremenek committed
  addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ);

  // Create the "autorelease" selector.
  Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : Autorelease);
Ted Kremenek's avatar
Ted Kremenek committed
  addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
  // For NSWindow, allocated objects are (initially) self-owned.  
  RetainSummary *NSWindowSumm =
    getPersistentSummary(RetEffect::MakeReceiverAlias(), SelfOwn);
  
  addInstMethSummary("NSWindow", NSWindowSumm, "initWithContentRect",
                     "styleMask", "backing", "defer", NULL);
  
  addInstMethSummary("NSWindow", NSWindowSumm, "initWithContentRect",
                     "styleMask", "backing", "defer", "screen", NULL);
    
  // For NSPanel (which subclasses NSWindow), allocated objects are not
  //  self-owned.
  addInstMethSummary("NSPanel", InitSumm, "initWithContentRect",
                     "styleMask", "backing", "defer", NULL);
  addInstMethSummary("NSPanel", InitSumm, "initWithContentRect",
                     "styleMask", "backing", "defer", "screen", NULL);
Ted Kremenek's avatar
Ted Kremenek committed

  // Create NSAssertionHandler summaries.
  addPanicSummary("NSAssertionHandler", "handleFailureInFunction", "file",
                  "lineNumber", "description", NULL); 
  
  addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object",
                  "file", "lineNumber", "description", NULL);
//===----------------------------------------------------------------------===//
// Reference-counting logic (typestate + counts).
//===----------------------------------------------------------------------===//

namespace {
  
  enum Kind {
    Owned = 0, // Owning reference.    
    NotOwned,  // Reference is not owned by still valid (not freed).    
    Released,  // Object has been released.
    ReturnedOwned, // Returned object passes ownership to caller.
    ReturnedNotOwned, // Return object does not pass ownership to caller.
    ErrorUseAfterRelease, // Object used after released.    
    ErrorReleaseNotOwned, // Release of an object that was not owned.
    ErrorLeak,  // A memory leak due to excessive reference counts.
    ErrorLeakReturned // A memory leak due to the returning method not having
                      // the correct naming conventions.            
Ted Kremenek's avatar
Ted Kremenek committed
  QualType T;

  RefVal(Kind k, unsigned cnt, QualType t) : kind(k), Cnt(cnt), T(t) {}
  RefVal(Kind k, unsigned cnt = 0) : kind(k), Cnt(cnt) {}
  Kind getKind() const { return kind; }
Ted Kremenek's avatar
Ted Kremenek committed
  unsigned getCount() const { return Cnt; }  
  QualType getType() const { return T; }
  static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
  
  static bool isLeak(Kind k) { return k >= ErrorLeak; }
  bool isNotOwned() const {
    return getKind() == NotOwned;
  }
  
  bool isReturnedOwned() const {
    return getKind() == ReturnedOwned;
  }
  
  bool isReturnedNotOwned() const {
    return getKind() == ReturnedNotOwned;
  }
  
  bool isNonLeakError() const {
    Kind k = getKind();
    return isError(k) && !isLeak(k);
  }
  
  // State creation: normal state.
  
Ted Kremenek's avatar
Ted Kremenek committed
  static RefVal makeOwned(QualType t, unsigned Count = 1) {
    return RefVal(Owned, Count, t);
Ted Kremenek's avatar
Ted Kremenek committed
  static RefVal makeNotOwned(QualType t, unsigned Count = 0) {
    return RefVal(NotOwned, Count, t);

  static RefVal makeReturnedOwned(unsigned Count) {
    return RefVal(ReturnedOwned, Count);
  }
  
  static RefVal makeReturnedNotOwned() {
    return RefVal(ReturnedNotOwned);
  }
  
  // Comparison, profiling, and pretty-printing.
  bool operator==(const RefVal& X) const {
Ted Kremenek's avatar
Ted Kremenek committed
    return kind == X.kind && Cnt == X.Cnt && T == X.T;
Ted Kremenek's avatar
Ted Kremenek committed
  RefVal operator-(size_t i) const {
    return RefVal(getKind(), getCount() - i, getType());
  }
  
  RefVal operator+(size_t i) const {
    return RefVal(getKind(), getCount() + i, getType());
  }
  
  RefVal operator^(Kind k) const {
    return RefVal(k, getCount(), getType());
  }
    
  
  void Profile(llvm::FoldingSetNodeID& ID) const {
    ID.AddInteger((unsigned) kind);
    ID.AddInteger(Cnt);
Ted Kremenek's avatar
Ted Kremenek committed
    ID.Add(T);
Ted Kremenek's avatar
Ted Kremenek committed
  if (!T.isNull())
    Out << "Tracked Type:" << T.getAsString() << '\n';
    
    case Owned: { 
      Out << "Owned";
      unsigned cnt = getCount();
      if (cnt) Out << " (+ " << cnt << ")";
      Out << "NotOwned";
      unsigned cnt = getCount();
      if (cnt) Out << " (+ " << cnt << ")";
      break;
    }
      
    case ReturnedOwned: { 
      Out << "ReturnedOwned";
      unsigned cnt = getCount();
      if (cnt) Out << " (+ " << cnt << ")";
    case ReturnedNotOwned: {
      Out << "ReturnedNotOwned";
      unsigned cnt = getCount();
      if (cnt) Out << " (+ " << cnt << ")";
      break;
    }
            
    case ErrorLeakReturned:
      Out << "Leaked (Bad naming)";
      break;
      
    case ErrorUseAfterRelease:
      Out << "Use-After-Release [ERROR]";
      break;
      
    case ErrorReleaseNotOwned:
      Out << "Release of Not-Owned [ERROR]";
      break;
  }
}
} // end anonymous namespace

//===----------------------------------------------------------------------===//
// RefBindings - State used to track object reference counts.
//===----------------------------------------------------------------------===//
  
typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
  template<>
  struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
    static inline void* GDMIndex() { return &RefBIndex; }  
  };
}

//===----------------------------------------------------------------------===//
// ARBindings - State used to track objects in autorelease pools.
//===----------------------------------------------------------------------===//

typedef llvm::ImmutableSet<SymbolRef> ARPoolContents;
typedef llvm::ImmutableList< std::pair<SymbolRef, ARPoolContents*> > ARBindings;
static int AutoRBIndex = 0;

namespace clang {
  template<>
  struct GRStateTrait<ARBindings> : public GRStatePartialTrait<ARBindings> {
    static inline void* GDMIndex() { return &AutoRBIndex; }  
  };
}

//===----------------------------------------------------------------------===//
// Transfer functions.
//===----------------------------------------------------------------------===//

class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
Ted Kremenek's avatar
Ted Kremenek committed
  // Type definitions.  
  typedef llvm::DenseMap<GRExprEngine::NodeTy*,std::pair<Expr*, SymbolRef> >
  typedef ReleasesNotOwnedTy UseAfterReleasesTy;
    
  typedef llvm::DenseMap<GRExprEngine::NodeTy*,
                         std::vector<std::pair<SymbolRef,bool> >*>
  class BindingsPrinter : public GRState::Printer {
    virtual void Print(std::ostream& Out, const GRState* state,
                       const char* nl, const char* sep);
  RetainSummaryManager Summaries;  
  const LangOptions&   LOpts;
  UseAfterReleasesTy   UseAfterReleases;
  ReleasesNotOwnedTy   ReleasesNotOwned;
  LeaksTy              Leaks;
  RefBindings Update(RefBindings B, SymbolRef sym, RefVal V, ArgEffect E,
                     RefVal::Kind& hasErr, RefBindings::Factory& RefBFactory);
  RefVal::Kind& Update(GRStateRef& state, SymbolRef sym, RefVal V,
                       ArgEffect E, RefVal::Kind& hasErr) {
    
    state = state.set<RefBindings>(Update(state.get<RefBindings>(), sym, V, 
                                          E, hasErr,
                                          state.get_context<RefBindings>()));
  void ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
                           GRStmtNodeBuilder<GRState>& Builder,
                           Expr* NodeExpr, Expr* ErrorExpr,                        
                           ExplodedNode<GRState>* Pred,
                           const GRState* St,
  std::pair<GRStateRef, bool>
  HandleSymbolDeath(GRStateManager& VMgr, const GRState* St,
                    const Decl* CD, SymbolRef sid, RefVal V, bool& hasLeak);
  CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
  virtual ~CFRefCount() {
    for (LeaksTy::iterator I = Leaks.begin(), E = Leaks.end(); I!=E; ++I)
      delete I->second;
  }
  
  virtual void RegisterChecks(GRExprEngine& Eng);
Ted Kremenek's avatar
Ted Kremenek committed
  virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {
    Printers.push_back(new BindingsPrinter());
  bool isGCEnabled() const { return Summaries.isGCEnabled(); }
  const LangOptions& getLangOptions() const { return LOpts; }
  
  void EvalSummary(ExplodedNodeSet<GRState>& Dst,
                   GRStmtNodeBuilder<GRState>& Builder,
                   Expr* Ex,
                   Expr* Receiver,
                   RetainSummary* Summ,
                   ExprIterator arg_beg, ExprIterator arg_end,                             
                   ExplodedNode<GRState>* Pred);
  virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
                        GRStmtNodeBuilder<GRState>& Builder,
                        ExplodedNode<GRState>* Pred);  
  virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
                                   GRStmtNodeBuilder<GRState>& Builder,
                                   ExplodedNode<GRState>* Pred);
  bool EvalObjCMessageExprAux(ExplodedNodeSet<GRState>& Dst,
                              GRStmtNodeBuilder<GRState>& Builder,
                              ExplodedNode<GRState>* Pred);
  virtual void EvalStore(ExplodedNodeSet<GRState>& Dst,
                         GRStmtNodeBuilder<GRState>& Builder,
                         Expr* E, ExplodedNode<GRState>* Pred,
                         const GRState* St, SVal TargetLV, SVal Val);
  // End-of-path.
  
  virtual void EvalEndPath(GRExprEngine& Engine,
                           GREndPathNodeBuilder<GRState>& Builder);
  virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
                               GRStmtNodeBuilder<GRState>& Builder,
                               ExplodedNode<GRState>* Pred,
                               Stmt* S, const GRState* state,
                               SymbolReaper& SymReaper);

  virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
                          GRStmtNodeBuilder<GRState>& Builder,
                          ExplodedNode<GRState>* Pred);
  virtual const GRState* EvalAssume(GRStateManager& VMgr,
                                       bool Assumption, bool& isFeasible);
  // Error iterators.

  typedef UseAfterReleasesTy::iterator use_after_iterator;  
  typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
  typedef LeaksTy::iterator            leaks_iterator;
  use_after_iterator use_after_begin() { return UseAfterReleases.begin(); }
  use_after_iterator use_after_end() { return UseAfterReleases.end(); }
  bad_release_iterator bad_release_begin() { return ReleasesNotOwned.begin(); }
  bad_release_iterator bad_release_end() { return ReleasesNotOwned.end(); }
  
  leaks_iterator leaks_begin() { return Leaks.begin(); }
  leaks_iterator leaks_end() { return Leaks.end(); }
void CFRefCount::BindingsPrinter::Print(std::ostream& Out, const GRState* state,
                                        const char* nl, const char* sep) {
    
  RefBindings B = state->get<RefBindings>();
    Out << sep << nl;
  
  for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
    Out << (*I).first << " : ";
    (*I).second.print(Out);
    Out << nl;
  }
}

static inline ArgEffect GetArgE(RetainSummary* Summ, unsigned idx) {
  return Summ ? Summ->getArg(idx) : MayEscape;
static inline RetEffect GetRetEffect(RetainSummary* Summ) {
  return Summ ? Summ->getRetEffect() : RetEffect::MakeNoRet();
static inline ArgEffect GetReceiverE(RetainSummary* Summ) {
  return Summ ? Summ->getReceiverEffect() : DoNothing;
}

static inline bool IsEndPath(RetainSummary* Summ) {
  return Summ ? Summ->isEndPath() : false;
}

void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
                                     GRStmtNodeBuilder<GRState>& Builder,
                                     Expr* NodeExpr, Expr* ErrorExpr,                        
                                     ExplodedNode<GRState>* Pred,
                                     const GRState* St,
  Builder.BuildSinks = true;
  GRExprEngine::NodeTy* N  = Builder.MakeNode(Dst, NodeExpr, Pred, St);

  if (!N) return;
    
  switch (hasErr) {
    default: assert(false);
    case RefVal::ErrorUseAfterRelease:
      UseAfterReleases[N] = std::make_pair(ErrorExpr, Sym);
      ReleasesNotOwned[N] = std::make_pair(ErrorExpr, Sym);
Ted Kremenek's avatar
Ted Kremenek committed
/// GetReturnType - Used to get the return type of a message expression or
///  function call with the intention of affixing that type to a tracked symbol.
///  While the the return type can be queried directly from RetEx, when
///  invoking class methods we augment to the return type to be that of
///  a pointer to the class (as opposed it just being id).
static QualType GetReturnType(Expr* RetE, ASTContext& Ctx) {

  QualType RetTy = RetE->getType();

  // FIXME: We aren't handling id<...>.
  const PointerType* PT = RetTy->getAsPointerType();
Ted Kremenek's avatar
Ted Kremenek committed
  if (!PT)
    return RetTy;
    
  // If RetEx is not a message expression just return its type.
  // If RetEx is a message expression, return its types if it is something
  /// more specific than id.
  
  ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(RetE);
  
  if (!ME || !Ctx.isObjCIdType(PT->getPointeeType()))
    return RetTy;
  
  ObjCInterfaceDecl* D = ME->getClassInfo().first;  

  // At this point we know the return type of the message expression is id.
  // If we have an ObjCInterceDecl, we know this is a call to a class method
  // whose type we can resolve.  In such cases, promote the return type to
  // Class*.  
  return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
}


void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
                             GRStmtNodeBuilder<GRState>& Builder,
                             Expr* Ex,
                             Expr* Receiver,
                             RetainSummary* Summ,
                             ExprIterator arg_beg, ExprIterator arg_end,                             
                             ExplodedNode<GRState>* Pred) {
  GRStateRef state(Builder.GetState(Pred), Eng.getStateManager());
  ASTContext& Ctx = Eng.getStateManager().getContext();

  // Evaluate the effect of the arguments.
  RefVal::Kind hasErr = (RefVal::Kind) 0;
  for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {    
      SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
      if (RefBindings::data_type* T = state.get<RefBindings>(Sym))
        if (Update(state, Sym, *T, GetArgE(Summ, idx), hasErr)) {
Ted Kremenek's avatar
Ted Kremenek committed
    }  
    else if (isa<Loc>(V)) {
      if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {

        if (GetArgE(Summ, idx) == DoNothingByRef)
          continue;
        
        // Invalidate the value of the variable passed by reference.
        
        // FIXME: Either this logic should also be replicated in GRSimpleVals
        //  or should be pulled into a separate "constraint engine."
        // FIXME: We can have collisions on the conjured symbol if the
        //  expression *I also creates conjured symbols.  We probably want
        //  to identify conjured symbols by an expression pair: the enclosing
        //  expression (the context) and the expression itself.  This should
        //  disambiguate conjured symbols. 
        const TypedRegion* R = dyn_cast<TypedRegion>(MR->getRegion());
        
        // Blast through AnonTypedRegions to get the original region type.
        while (R) {
          const AnonTypedRegion* ATR = dyn_cast<AnonTypedRegion>(R);
          if (!ATR) break;
          R = dyn_cast<TypedRegion>(ATR->getSuperRegion());
        }
        
          
          // Is the invalidated variable something that we were tracking?
          SVal X = state.GetSVal(Loc::MakeVal(R));
          
          if (isa<loc::SymbolVal>(X)) {
            SymbolRef Sym = cast<loc::SymbolVal>(X).getSymbol();
            state = state.remove<RefBindings>(Sym);
          }
          
          // Set the value of the variable to be a conjured symbol.
          unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek's avatar
Ted Kremenek committed
          QualType T = R->getRValueType(Ctx);
          if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
              Eng.getSymbolManager().getConjuredSymbol(*I, T, Count);
            
            state = state.BindLoc(Loc::MakeVal(R),
                                  Loc::IsLocType(T)
                                  ? cast<SVal>(loc::SymbolVal(NewSym))
                                  : cast<SVal>(nonloc::SymbolVal(NewSym)));
          }
          else {
            state = state.BindLoc(*MR, UnknownVal());
          state = state.BindLoc(*MR, UnknownVal());
      }
      else {
        // Nuke all other arguments passed by reference.
Ted Kremenek's avatar
Ted Kremenek committed
    }
    else if (isa<nonloc::LocAsInteger>(V))
      state = state.Unbind(cast<nonloc::LocAsInteger>(V).getLoc());
Ted Kremenek's avatar
Ted Kremenek committed
  // Evaluate the effect on the message receiver.  
  if (!ErrorExpr && Receiver) {
    SVal V = state.GetSVal(Receiver);
    if (isa<loc::SymbolVal>(V)) {
      SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
      if (const RefVal* T = state.get<RefBindings>(Sym))
        if (Update(state, Sym, *T, GetReceiverE(Summ), hasErr)) {
          ErrorExpr = Receiver;
Ted Kremenek's avatar
Ted Kremenek committed
  // Process any errors.  
    ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state,
  // Consult the summary for the return value.  
  RetEffect RE = GetRetEffect(Summ);
  
  switch (RE.getKind()) {
    default:
      assert (false && "Unhandled RetEffect."); break;
      // Make up a symbol for the return value (not reference counted).
Ted Kremenek's avatar
Ted Kremenek committed
      // FIXME: This is basically copy-and-paste from GRSimpleVals.  We 
      //  should compose behavior, not copy it.
      // FIXME: We eventually should handle structs and other compound types
      // that are returned by value.
      
      QualType T = Ex->getType();
      
      if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
        unsigned Count = Builder.getCurrentBlockCount();
        SymbolRef Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
        SVal X = Loc::IsLocType(Ex->getType())
               ? cast<SVal>(loc::SymbolVal(Sym)) 
               : cast<SVal>(nonloc::SymbolVal(Sym));
        state = state.BindExpr(Ex, X, false);
    case RetEffect::Alias: {
Ted Kremenek's avatar
Ted Kremenek committed
      unsigned idx = RE.getIndex();
      assert (idx < (unsigned) (arg_end - arg_beg));
      SVal V = state.GetSVal(*(arg_beg+idx));
      state = state.BindExpr(Ex, V, false);
    case RetEffect::ReceiverAlias: {
      assert (Receiver);
      state = state.BindExpr(Ex, V, false);
    case RetEffect::OwnedAllocatedSymbol:
    case RetEffect::OwnedSymbol: {
      unsigned Count = Builder.getCurrentBlockCount();
      SymbolRef Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
Ted Kremenek's avatar
Ted Kremenek committed
      QualType RetT = GetReturnType(Ex, Eng.getContext());
      state = state.set<RefBindings>(Sym, RefVal::makeOwned(RetT));
      state = state.BindExpr(Ex, loc::SymbolVal(Sym), false);
      RefBindings B = GetRefBindings(StImpl);
Ted Kremenek's avatar
Ted Kremenek committed
      SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(RetT)));
      // FIXME: Add a flag to the checker where allocations are allowed to fail.      
      if (RE.getKind() == RetEffect::OwnedAllocatedSymbol)
        state = state.AddNE(Sym, Eng.getBasicVals().getZeroWithPtrWidth());
      break;
    }
      
    case RetEffect::NotOwnedSymbol: {
      unsigned Count = Builder.getCurrentBlockCount();
      SymbolRef Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
Ted Kremenek's avatar
Ted Kremenek committed
      QualType RetT = GetReturnType(Ex, Eng.getContext());
      state = state.set<RefBindings>(Sym, RefVal::makeNotOwned(RetT));
      state = state.BindExpr(Ex, loc::SymbolVal(Sym), false);
  // Is this a sink?
  if (IsEndPath(Summ))
    Builder.MakeSinkNode(Dst, Ex, Pred, state);
    Builder.MakeNode(Dst, Ex, Pred, state);
void CFRefCount::EvalCall(ExplodedNodeSet<GRState>& Dst,
                          GRStmtNodeBuilder<GRState>& Builder,
                          ExplodedNode<GRState>* Pred) {
  RetainSummary* Summ = !isa<loc::FuncVal>(L) ? 0
                      : Summaries.getSummary(cast<loc::FuncVal>(L).getDecl());
  
  EvalSummary(Dst, Eng, Builder, CE, 0, Summ,
              CE->arg_begin(), CE->arg_end(), Pred);
void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
                                     GRStmtNodeBuilder<GRState>& Builder,
                                     ExplodedNode<GRState>* Pred) {  
Ted Kremenek's avatar
Ted Kremenek committed
  if (Expr* Receiver = ME->getReceiver()) {
    // We need the type-information of the tracked receiver object
    // Retrieve it from the state.
    ObjCInterfaceDecl* ID = 0;

    // FIXME: Wouldn't it be great if this code could be reduced?  It's just
    // a chain of lookups.
    const GRState* St = Builder.GetState(Pred);
    SVal V = Eng.getStateManager().GetSVal(St, Receiver );
Ted Kremenek's avatar
Ted Kremenek committed

      SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
Ted Kremenek's avatar
Ted Kremenek committed
      
      if (const RefVal* T  = St->get<RefBindings>(Sym)) {
Ted Kremenek's avatar
Ted Kremenek committed
        
        if (const PointerType* PT = Ty->getAsPointerType()) {
          QualType PointeeTy = PT->getPointeeType();
          
          if (ObjCInterfaceType* IT = dyn_cast<ObjCInterfaceType>(PointeeTy))
            ID = IT->getDecl();
        }
      }
    }
    
    Summ = Summaries.getMethodSummary(ME, ID);
    // Special-case: are we sending a mesage to "self"?
    //  This is a hack.  When we have full-IP this should be removed.
    if (!Summ) {
      ObjCMethodDecl* MD = 
        dyn_cast<ObjCMethodDecl>(&Eng.getGraph().getCodeDecl());
      
      if (MD) {
        if (Expr* Receiver = ME->getReceiver()) {
          SVal X = Eng.getStateManager().GetSVal(St, Receiver);
          if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X))
            if (L->getRegion() == Eng.getStateManager().getSelfRegion(St)) {
              // Create a summmary where all of the arguments "StopTracking".
              Summ = Summaries.getPersistentSummary(RetEffect::MakeNoRet(),
                                                    DoNothing,
                                                    StopTracking);
            }
Ted Kremenek's avatar
Ted Kremenek committed
  }
    Summ = Summaries.getClassMethodSummary(ME->getClassName(),
                                           ME->getSelector());
  EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), Summ,
              ME->arg_begin(), ME->arg_end(), Pred);
void CFRefCount::EvalStore(ExplodedNodeSet<GRState>& Dst,
                           GRStmtNodeBuilder<GRState>& Builder,
                           Expr* E, ExplodedNode<GRState>* Pred,
                           const GRState* St, SVal TargetLV, SVal Val) {
  
  // Check if we have a binding for "Val" and if we are storing it to something
  // we don't understand or otherwise the value "escapes" the function.
  
    return;
  
  // Are we storing to something that causes the value to "escape"?
  
  bool escapes = false;
  
  // A value escapes in three possible cases (this may change):
  //
  // (1) we are binding to something that is not a memory region.
  // (2) we are binding to a memregion that does not have stack storage
  // (3) we are binding to a memregion with stack storage that the store
  //     does not understand.
  
  SymbolRef Sym = cast<loc::SymbolVal>(Val).getSymbol();
  GRStateRef state(St, Eng.getStateManager());

  if (!isa<loc::MemRegionVal>(TargetLV))
    const MemRegion* R = cast<loc::MemRegionVal>(TargetLV).getRegion();
    escapes = !Eng.getStateManager().hasStackStorage(R);
    
    if (!escapes) {
      // To test (3), generate a new state with the binding removed.  If it is
      // the same state, then it escapes (since the store cannot represent
      // the binding).
      GRStateRef stateNew = state.BindLoc(cast<Loc>(TargetLV), Val);

  // Do we have a reference count binding?
  // FIXME: Is this step even needed?  We do blow away the binding anyway.
  // Hand of the remaining logic to the parent implementation.
  GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, state, TargetLV, Val);
std::pair<GRStateRef,bool>
CFRefCount::HandleSymbolDeath(GRStateManager& VMgr,
                              const GRState* St, const Decl* CD,
  assert ((!V.isReturnedOwned() || CD) &&
          "CodeDecl must be available for reporting ReturnOwned errors.");
  if (V.isReturnedOwned() && V.getCount() == 0)
    if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
      std::string s = MD->getSelector().getAsString();
      if (!followsReturnRule(s.c_str())) {
        state = state.set<RefBindings>(sid, V ^ RefVal::ErrorLeakReturned);
        return std::make_pair(state, true);
  // All other cases.
  
  hasLeak = V.isOwned() || 
            ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
    return std::make_pair(state.remove<RefBindings>(sid), false);
  return std::make_pair(state.set<RefBindings>(sid, V ^ RefVal::ErrorLeak),
                        false);
}

void CFRefCount::EvalEndPath(GRExprEngine& Eng,
                             GREndPathNodeBuilder<GRState>& Builder) {
  const GRState* St = Builder.getState();
  RefBindings B = St->get<RefBindings>();
  llvm::SmallVector<std::pair<SymbolRef, bool>, 10> Leaked;
  const Decl* CodeDecl = &Eng.getGraph().getCodeDecl();
  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
    bool hasLeak = false;
    std::pair<GRStateRef, bool> X =
      HandleSymbolDeath(Eng.getStateManager(), St, CodeDecl,
                        (*I).first, (*I).second, hasLeak);
    St = X.first;
    if (hasLeak) Leaked.push_back(std::make_pair((*I).first, X.second));
  ExplodedNode<GRState>* N = Builder.MakeNode(St);  
  std::vector<std::pair<SymbolRef,bool> >*& LeaksAtNode = Leaks[N];
  LeaksAtNode = new std::vector<std::pair<SymbolRef,bool> >();
  for (llvm::SmallVector<std::pair<SymbolRef,bool>, 10>::iterator
       I = Leaked.begin(), E = Leaked.end(); I != E; ++I)
void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
                                 GRStmtNodeBuilder<GRState>& Builder,
                                 ExplodedNode<GRState>* Pred,
                                 const GRState* St,
  // FIXME: a lot of copy-and-paste from EvalEndPath.  Refactor.
  
  RefBindings B = St->get<RefBindings>();
  llvm::SmallVector<std::pair<SymbolRef,bool>, 10> Leaked;
  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
        E = SymReaper.dead_end(); I != E; ++I) {
    std::pair<GRStateRef, bool> X
      = HandleSymbolDeath(Eng.getStateManager(), St, 0, *I, *T, hasLeak);
    
    St = X.first;
      Leaked.push_back(std::make_pair(*I,X.second));    
  ExplodedNode<GRState>* N = Builder.MakeNode(Dst, S, Pred, St);  
  std::vector<std::pair<SymbolRef,bool> >*& LeaksAtNode = Leaks[N];
  LeaksAtNode = new std::vector<std::pair<SymbolRef,bool> >();
  for (llvm::SmallVector<std::pair<SymbolRef,bool>, 10>::iterator
       I = Leaked.begin(), E = Leaked.end(); I != E; ++I)
void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst,
                            GRStmtNodeBuilder<GRState>& Builder,
                            ExplodedNode<GRState>* Pred) {
  GRStateRef state(Builder.GetState(Pred), Eng.getStateManager());
    return;
  
  // Get the reference count binding (if any).
  SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
  const RefVal* T = state.get<RefBindings>(Sym);
    case RefVal::Owned: { 
      unsigned cnt = X.getCount();
      assert (cnt > 0);
      X = RefVal::makeReturnedOwned(cnt - 1);
      break;
    }
      
    case RefVal::NotOwned: {
      unsigned cnt = X.getCount();
      X = cnt ? RefVal::makeReturnedOwned(cnt - 1)
              : RefVal::makeReturnedNotOwned();
      break;
    }
      
    default: 
      return;
  }
  
  // Update the binding.