Fix: <rdar://problem/5905851> do not report a leak when post-dominated by a call

to a noreturn or panic function


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81803 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2009-09-14 22:01:32 +00:00
Родитель 31fddcca28
Коммит 06c9cb4d1a
3 изменённых файлов: 121 добавлений и 12 удалений

Просмотреть файл

@ -189,13 +189,21 @@ private:
const std::string Category; const std::string Category;
llvm::FoldingSet<BugReportEquivClass> EQClasses; llvm::FoldingSet<BugReportEquivClass> EQClasses;
friend class BugReporter; friend class BugReporter;
bool SuppressonSink;
public: public:
BugType(const char *name, const char* cat) : Name(name), Category(cat) {} BugType(const char *name, const char* cat)
: Name(name), Category(cat), SuppressonSink(false) {}
virtual ~BugType(); virtual ~BugType();
// FIXME: Should these be made strings as well? // FIXME: Should these be made strings as well?
const std::string& getName() const { return Name; } const std::string& getName() const { return Name; }
const std::string& getCategory() const { return Category; } const std::string& getCategory() const { return Category; }
/// isSuppressOnSink - Returns true if bug reports associated with this bug
/// type should be suppressed if the end node of the report is post-dominated
/// by a sink node.
bool isSuppressOnSink() const { return SuppressonSink; }
void setSuppressOnSink(bool x) { SuppressonSink = x; }
virtual void FlushReports(BugReporter& BR); virtual void FlushReports(BugReporter& BR);

Просмотреть файл

@ -1639,34 +1639,131 @@ void BugReporter::EmitReport(BugReport* R) {
EQ->AddReport(R); EQ->AddReport(R);
} }
//===----------------------------------------------------------------------===//
// Emitting reports in equivalence classes.
//===----------------------------------------------------------------------===//
namespace {
struct VISIBILITY_HIDDEN FRIEC_WLItem {
const ExplodedNode *N;
ExplodedNode::const_succ_iterator I, E;
FRIEC_WLItem(const ExplodedNode *n)
: N(n), I(N->succ_begin()), E(N->succ_end()) {}
};
}
static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) {
BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
assert(I != E);
BugReport *R = *I;
BugType& BT = R->getBugType();
if (!BT.isSuppressOnSink())
return R;
// For bug reports that should be suppressed when all paths are post-dominated
// by a sink node, iterate through the reports in the equivalence class
// until we find one that isn't post-dominated (if one exists). We use a
// DFS traversal of the ExplodedGraph to find a non-sink node. We could write
// this as a recursive function, but we don't want to risk blowing out the
// stack for very long paths.
for (; I != E; ++I) {
R = *I;
const ExplodedNode *N = R->getEndNode();
if (!N)
continue;
if (N->isSink()) {
assert(false &&
"BugType::isSuppressSink() should not be 'true' for sink end nodes");
return R;
}
if (N->succ_empty())
return R;
// At this point we know that 'N' is not a sink and it has at least one
// successor. Use a DFS worklist to find a non-sink end-of-path node.
typedef FRIEC_WLItem WLItem;
typedef llvm::SmallVector<WLItem, 10> DFSWorkList;
llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
DFSWorkList WL;
WL.push_back(N);
Visited[N] = 1;
while (!WL.empty()) {
WLItem &WI = WL.back();
assert(!WI.N->succ_empty());
for (; WI.I != WI.E; ++WI.I) {
const ExplodedNode *Succ = *WI.I;
// End-of-path node?
if (Succ->succ_empty()) {
// If we found an end-of-path node that is not a sink, then return
// this report.
if (!Succ->isSink())
return R;
// Found a sink? Continue on to the next successor.
continue;
}
// Mark the successor as visited. If it hasn't been explored,
// enqueue it to the DFS worklist.
unsigned &mark = Visited[Succ];
if (!mark) {
mark = 1;
WL.push_back(Succ);
break;
}
}
if (&WL.back() == &WI)
WL.pop_back();
}
}
// If we reach here, the end nodes for all reports in the equiavalence
// class are post-dominated by a sink node.
return NULL;
}
void BugReporter::FlushReport(BugReportEquivClass& EQ) { void BugReporter::FlushReport(BugReportEquivClass& EQ) {
assert(!EQ.Reports.empty()); BugReport *R = FindReportInEquivalenceClass(EQ);
BugReport &R = **EQ.begin();
if (!R)
return;
PathDiagnosticClient* PD = getPathDiagnosticClient(); PathDiagnosticClient* PD = getPathDiagnosticClient();
// FIXME: Make sure we use the 'R' for the path that was actually used. // FIXME: Make sure we use the 'R' for the path that was actually used.
// Probably doesn't make a difference in practice. // Probably doesn't make a difference in practice.
BugType& BT = R.getBugType(); BugType& BT = R->getBugType();
llvm::OwningPtr<PathDiagnostic> llvm::OwningPtr<PathDiagnostic>
D(new PathDiagnostic(R.getBugType().getName(), D(new PathDiagnostic(R->getBugType().getName(),
!PD || PD->useVerboseDescription() !PD || PD->useVerboseDescription()
? R.getDescription() : R.getShortDescription(), ? R->getDescription() : R->getShortDescription(),
BT.getCategory())); BT.getCategory()));
GeneratePathDiagnostic(*D.get(), EQ); GeneratePathDiagnostic(*D.get(), EQ);
// Get the meta data. // Get the meta data.
std::pair<const char**, const char**> Meta = R.getExtraDescriptiveText(); std::pair<const char**, const char**> Meta = R->getExtraDescriptiveText();
for (const char** s = Meta.first; s != Meta.second; ++s) D->addMeta(*s); for (const char** s = Meta.first; s != Meta.second; ++s)
D->addMeta(*s);
// Emit a summary diagnostic to the regular Diagnostics engine. // Emit a summary diagnostic to the regular Diagnostics engine.
const SourceRange *Beg = 0, *End = 0; const SourceRange *Beg = 0, *End = 0;
R.getRanges(Beg, End); R->getRanges(Beg, End);
Diagnostic& Diag = getDiagnostic(); Diagnostic& Diag = getDiagnostic();
FullSourceLoc L(R.getLocation(), getSourceManager()); FullSourceLoc L(R->getLocation(), getSourceManager());
unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
R.getShortDescription().c_str()); R->getShortDescription().c_str());
switch (End-Beg) { switch (End-Beg) {
default: assert(0 && "Don't handle this many ranges yet!"); default: assert(0 && "Don't handle this many ranges yet!");
@ -1682,7 +1779,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
if (D->empty()) { if (D->empty()) {
PathDiagnosticPiece* piece = PathDiagnosticPiece* piece =
new PathDiagnosticEventPiece(L, R.getDescription()); new PathDiagnosticEventPiece(L, R->getDescription());
for ( ; Beg != End; ++Beg) piece->addRange(*Beg); for ( ; Beg != End; ++Beg) piece->addRange(*Beg);
D->push_back(piece); D->push_back(piece);

Просмотреть файл

@ -2216,7 +2216,9 @@ void CFRefCount::RegisterChecks(BugReporter& BR) {
name = "Leak of returned object"; name = "Leak of returned object";
} }
// Leaks should not be reported if they are post-dominated by a sink.
leakAtReturn = new LeakAtReturn(this, name); leakAtReturn = new LeakAtReturn(this, name);
leakAtReturn->setSuppressOnSink(true);
BR.Register(leakAtReturn); BR.Register(leakAtReturn);
// Second, register leaks within a function/method. // Second, register leaks within a function/method.
@ -2230,7 +2232,9 @@ void CFRefCount::RegisterChecks(BugReporter& BR) {
name = "Leak"; name = "Leak";
} }
// Leaks should not be reported if they are post-dominated by sinks.
leakWithinFunction = new LeakWithinFunction(this, name); leakWithinFunction = new LeakWithinFunction(this, name);
leakWithinFunction->setSuppressOnSink(true);
BR.Register(leakWithinFunction); BR.Register(leakWithinFunction);
// Save the reference to the BugReporter. // Save the reference to the BugReporter.