Skip to content
CFRefCount.cpp 62.1 KiB
Newer Older

    VarDecl* VD = 0;
    
    // Determine if there is an LVal binding to the symbol.
    for (ValueState::vb_iterator I=St->vb_begin(), E=St->vb_end(); I!=E; ++I) {
      if (!isa<lval::SymbolVal>(I->second)  // Is the value a symbol?
          || cast<lval::SymbolVal>(I->second).getSymbol() != Sym)
        continue;
      
      if (VD) {  // Multiple decls map to this symbol.
        VD = 0;
        break;
      }
      
      VD = I->first;
    }
    
    if (VD) FirstDecl = VD;
  
  assert (Last);
  Stmt* FirstStmt = cast<PostStmt>(Last->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);
}

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

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