diff options
author | Ted Kremenek <kremenek@apple.com> | 2008-04-18 04:55:01 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2008-04-18 04:55:01 +0000 |
commit | 2cf943a6ac475a08c25a7ca0ca93be5845093cba (patch) | |
tree | f6926d305d202d680f5acda37247715fd84a73db /lib/Analysis/CFRefCount.cpp | |
parent | 5c176f7a9ba9f7084b903393845be24f85e091da (diff) |
Added path diagnostics for reference counts.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49892 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CFRefCount.cpp')
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 110 |
1 files changed, 101 insertions, 9 deletions
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 0c5860ecda..41754c95e7 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/ImmutableMap.h" #include "llvm/Support/Compiler.h" #include <ostream> +#include <sstream> using namespace clang; @@ -1235,11 +1236,11 @@ namespace { UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {} virtual const char* getName() const { - return "(CoreFoundation) use-after-release"; + return "Core Foundation: Use-After-Release"; } virtual const char* getDescription() const { - return "(CoreFoundation) Reference-counted object is used" - " after it is released."; + return "Reference-counted object is used" + " after it is released."; } virtual void EmitWarnings(BugReporter& BR); @@ -1251,11 +1252,11 @@ namespace { BadRelease(CFRefCount& tf) : CFRefBug(tf) {} virtual const char* getName() const { - return "(CoreFoundation) release of non-owned object"; + return "Core Foundation: Release of non-owned object"; } virtual const char* getDescription() const { return "Incorrect decrement of the reference count of a " - "CoreFoundation object:\n" + "CoreFoundation object: " "The object is not owned at this point by the caller."; } @@ -1267,12 +1268,11 @@ namespace { Leak(CFRefCount& tf) : CFRefBug(tf) {} virtual const char* getName() const { - return "(CoreFoundation) Memory Leak"; + return "Core Foundation: Memory Leak"; } virtual const char* getDescription() const { - return "The CoreFoundation object has an excessive reference count and" - "\nis leaked after this statement."; + return "Object leaked."; } virtual void EmitWarnings(BugReporter& BR); @@ -1320,10 +1320,102 @@ PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<ValueState>* N, CFRefCount::RefBindings PrevB = CFRefCount::GetRefBindings(*PrevSt); CFRefCount::RefBindings CurrB = CFRefCount::GetRefBindings(*CurrSt); + CFRefCount::RefBindings::TreeTy* PrevT = PrevB.SlimFind(Sym); + CFRefCount::RefBindings::TreeTy* CurrT = CurrB.SlimFind(Sym); + if (!CurrT) + return NULL; + const char* Msg = NULL; + RefVal CurrV = CurrB.SlimFind(Sym)->getValue().second; - return NULL; + if (!PrevT) { + + // Check for the point where we start tracking the value. + + if (CurrV.isOwned()) + Msg = "Function call returns 'Owned' Core Foundation object."; + else { + assert (CurrV.isNotOwned()); + Msg = "Function call returns 'Non-Owned' Core Foundation object."; + } + + Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); + FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager()); + PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg); + + if (Expr* Exp = dyn_cast<Expr>(S)) + P->addRange(Exp->getSourceRange()); + + return P; + } + + // Determine if the typestate has changed. + + RefVal PrevV = PrevB.SlimFind(Sym)->getValue().second; + + if (PrevV == CurrV) + return NULL; + + // The typestate has changed. + + std::ostringstream os; + + switch (CurrV.getKind()) { + case RefVal::Owned: + case RefVal::NotOwned: + assert (PrevV.getKind() == CurrV.getKind()); + + if (PrevV.getCount() > CurrV.getCount()) + os << "Reference count decremented."; + else + os << "Reference count incremented."; + + if (CurrV.getCount()) + os << " Object has +" << CurrV.getCount() << " reference counts."; + + Msg = os.str().c_str(); + + break; + + case RefVal::Released: + Msg = "Object released."; + break; + + case RefVal::ReturnedOwned: + Msg = "Object returned to caller. " + "Caller gets ownership of object."; + break; + + case RefVal::ReturnedNotOwned: + Msg = "Object returned to caller. " + "Caller does not get ownership of object."; + break; + + default: + return NULL; + } + + Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); + FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager()); + PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg); + + // Add the range by scanning the children of the statement for any bindings + // to Sym. + + ValueStateManager& VSM = BR.getEngine().getStateManager(); + + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) + if (Expr* Exp = dyn_cast_or_null<Expr>(*I)) { + RVal X = VSM.GetRVal(CurrSt, Exp); + + if (lval::SymbolVal* SV = dyn_cast<lval::SymbolVal>(&X)) + if (SV->getSymbol() == Sym) { + P->addRange(Exp->getSourceRange()); break; + } + } + + return P; } void UseAfterRelease::EmitWarnings(BugReporter& BR) { |