Skip to content
CFRefCount.cpp 63.6 KiB
Newer Older
      if (VD) {  // Multiple decls map to this symbol.
        VD = 0;
        break;
      }
      
      VD = I->first;
    }
    
    if (VD) FirstDecl = VD;
    Last = N;
    N = N->pred_empty() ? NULL : *(N->pred_begin());    
  }
  
  return std::make_pair(Last, FirstDecl);
}

PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
                                             ExplodedNode<ValueState>* EndN) {

  // Tell the BugReporter to report cases when the tracked symbol is
  // assigned to different variables, etc.
  BR.addNotableSymbol(Sym);
  if (!getBugType().isLeak())
    return RangedBugReport::getEndPath(BR, EndN);

  typedef CFRefCount::RefBindings RefBindings;

  // Get the retain count.
  unsigned long RetCount = 0;
  
  {
    ValueState* St = EndN->getState();
    RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
    RefBindings::TreeTy* T = B.SlimFind(Sym);
    assert (T);
    RetCount = T->getValue().second.getCount();
  }

  // We are a leak.  Walk up the graph to get to the first node where the
  // symbol appeared, and also get the first VarDecl that tracked object
  // is stored to.

  ExplodedNode<ValueState>* AllocNode = 0;
  VarDecl* FirstDecl = 0;
  llvm::tie(AllocNode, FirstDecl) = GetAllocationSite(EndN, Sym);
  
  // Get the allocate site.  
  assert (AllocNode);
  Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt();
  SourceManager& SMgr = BR.getContext().getSourceManager();
  unsigned AllocLine = SMgr.getLogicalLineNumber(FirstStmt->getLocStart());

  // Get the leak site.  We may have multiple ExplodedNodes (one with the
  // leak) that occur on the same line number; if the node with the leak
  // has any immediate predecessor nodes with the same line number, find
  // any transitive-successors that have a different statement and use that
  // line number instead.  This avoids emiting a diagnostic like:
  //
  //    // 'y' is leaked.
  //  int x = foo(y);
  //
  //  instead we want:
  //
  //  int x = foo(y);
  //   // 'y' is leaked.
  
  Stmt* S = getStmt(BR);  // This is the statement where the leak occured.
  assert (S);
  unsigned EndLine = SMgr.getLogicalLineNumber(S->getLocStart());

  // Look in the *trimmed* graph at the immediate predecessor of EndN.  Does
  // it occur on the same line?

  PathDiagnosticPiece::DisplayHint Hint = PathDiagnosticPiece::Above;
  
  assert (!EndN->pred_empty()); // Not possible to have 0 predecessors.
  ExplodedNode<ValueState> *Pred = *(EndN->pred_begin());
  ProgramPoint PredPos = Pred->getLocation();
  if (PostStmt* PredPS = dyn_cast<PostStmt>(&PredPos)) {
    Stmt* SPred = PredPS->getStmt();
    if (SMgr.getLogicalLineNumber(SPred->getLocStart()) != EndLine) {
      Hint = PathDiagnosticPiece::Below;
      S = SPred;
    }
  FullSourceLoc L( S->getLocStart(), SMgr);
  os << "Object allocated on line " << AllocLine;
  
  if (FirstDecl)
    os << " and stored into '" << FirstDecl->getName() << '\'';
    
Ted Kremenek's avatar
Ted Kremenek committed
  os << " is no longer referenced after this point and has a retain count of +"
     << RetCount << " (object leaked).";
  return new PathDiagnosticPiece(L, os.str(), Hint);
void UseAfterRelease::EmitWarnings(BugReporter& BR) {
  for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
        E = TF.use_after_end(); I != E; ++I) {
    
    CFRefReport report(*this, I->first, I->second.second);
    report.addRange(I->second.first->getSourceRange());    
}

void BadRelease::EmitWarnings(BugReporter& BR) {
  for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
       E = TF.bad_release_end(); I != E; ++I) {
    
    CFRefReport report(*this, I->first, I->second.second);
    report.addRange(I->second.first->getSourceRange());    
    BR.EmitWarning(report);    
void Leak::EmitWarnings(BugReporter& BR) {
  
  for (CFRefCount::leaks_iterator I = TF.leaks_begin(),
       E = TF.leaks_end(); I != E; ++I) {
    
    std::vector<SymbolID>& SymV = *(I->second);
    unsigned n = SymV.size();
    
    for (unsigned i = 0; i < n; ++i) {
      CFRefReport report(*this, I->first, SymV[i]);
      BR.EmitWarning(report);
    }
void Leak::GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {
  for (CFRefCount::leaks_iterator I=TF.leaks_begin(), E=TF.leaks_end();
       I!=E; ++I)
    Nodes.push_back(I->first);
}

bool Leak::isCached(BugReport& R) {
  
  // Most bug reports are cached at the location where they occured.
  // With leaks, we want to unique them by the location where they were
  // allocated, and only report only a single path.
  
  SymbolID Sym = static_cast<CFRefReport&>(R).getSymbol();

  ExplodedNode<ValueState>* AllocNode =
    GetAllocationSite(R.getEndNode(), Sym).first;
  
  if (!AllocNode)
    return false;
  
  return BugTypeCacheLocation::isCached(AllocNode->getLocation());
}

//===----------------------------------------------------------------------===//
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//

GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
  return new CFRefCount(Ctx, GCEnabled, StandardWarnings, lopts);