[analyzer] Fix an assertation failure for invalid sourcelocation, add a new debug checker
For a rather short code snippet, if debug.ReportStmts (added in this patch) was enabled, a bug reporter visitor crashed: struct h { operator int(); }; int k() { return h(); } Ultimately, this originated from PathDiagnosticLocation::createMemberLoc, as it didn't handle the case where it's MemberExpr typed parameter returned and invalid SourceLocation for MemberExpr::getMemberLoc. The solution was to find any related valid SourceLocaion, and Stmt::getBeginLoc happens to be just that. Differential Revision: https://reviews.llvm.org/D58777 llvm-svn: 356161
This commit is contained in:
parent
ac093d61c4
commit
4962816e72
|
@ -285,3 +285,10 @@ There is also an additional -analyzer-stats flag, which enables various
|
||||||
statistics within the analyzer engine. Note the Stats checker (which produces at
|
statistics within the analyzer engine. Note the Stats checker (which produces at
|
||||||
least one bug report per function) may actually change the values reported by
|
least one bug report per function) may actually change the values reported by
|
||||||
-analyzer-stats.
|
-analyzer-stats.
|
||||||
|
|
||||||
|
Output testing checkers
|
||||||
|
=======================
|
||||||
|
|
||||||
|
- debug.ReportStmts reports a warning at **every** statement, making it a very
|
||||||
|
useful tool for testing thoroughly bug report construction and output
|
||||||
|
emission.
|
||||||
|
|
|
@ -1019,6 +1019,10 @@ def ExplodedGraphViewer : Checker<"ViewExplodedGraph">,
|
||||||
HelpText<"View Exploded Graphs using GraphViz">,
|
HelpText<"View Exploded Graphs using GraphViz">,
|
||||||
Documentation<NotDocumented>;
|
Documentation<NotDocumented>;
|
||||||
|
|
||||||
|
def ReportStmts : Checker<"ReportStmts">,
|
||||||
|
HelpText<"Emits a warning for every statement.">,
|
||||||
|
Documentation<NotDocumented>;
|
||||||
|
|
||||||
} // end "debug"
|
} // end "debug"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -266,3 +266,34 @@ void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
|
||||||
bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) {
|
bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Emits a report for every Stmt that the analyzer visits.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ReportStmts : public Checker<check::PreStmt<Stmt>> {
|
||||||
|
BuiltinBug BT_stmtLoc{this, "Statement"};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void checkPreStmt(const Stmt *S, CheckerContext &C) const {
|
||||||
|
ExplodedNode *Node = C.generateNonFatalErrorNode();
|
||||||
|
if (!Node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node);
|
||||||
|
|
||||||
|
C.emitReport(std::move(Report));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
|
void ento::registerReportStmts(CheckerManager &mgr) {
|
||||||
|
mgr.registerChecker<ReportStmts>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ento::shouldRegisterReportStmts(const LangOptions &LO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -571,6 +571,8 @@ static SourceLocation getValidSourceLocation(const Stmt* S,
|
||||||
} while (!L.isValid());
|
} while (!L.isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Ironically, this assert actually fails in some cases.
|
||||||
|
//assert(L.isValid());
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,7 +673,15 @@ PathDiagnosticLocation::createConditionalColonLoc(
|
||||||
PathDiagnosticLocation
|
PathDiagnosticLocation
|
||||||
PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
|
PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
|
||||||
const SourceManager &SM) {
|
const SourceManager &SM) {
|
||||||
|
|
||||||
|
assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid());
|
||||||
|
|
||||||
|
// In some cases, getMemberLoc isn't valid -- in this case we'll return with
|
||||||
|
// some other related valid SourceLocation.
|
||||||
|
if (ME->getMemberLoc().isValid())
|
||||||
return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
|
return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
|
||||||
|
|
||||||
|
return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathDiagnosticLocation
|
PathDiagnosticLocation
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// RUN: %clang_analyze_cc1 -verify %s \
|
||||||
|
// RUN: -analyzer-output=plist -o %t.plist \
|
||||||
|
// RUN: -analyzer-checker=core \
|
||||||
|
// RUN: -analyzer-checker=debug.ReportStmts
|
||||||
|
|
||||||
|
struct h {
|
||||||
|
operator int();
|
||||||
|
};
|
||||||
|
|
||||||
|
int k() {
|
||||||
|
return h(); // expected-warning 3 {{Statement}}
|
||||||
|
}
|
|
@ -3,7 +3,10 @@
|
||||||
|
|
||||||
// RUN: rm -rf %t.dir
|
// RUN: rm -rf %t.dir
|
||||||
// RUN: mkdir -p %t.dir
|
// RUN: mkdir -p %t.dir
|
||||||
// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-html -o %t.dir/index.plist %s
|
//
|
||||||
|
// RUN: %clang_analyze_cc1 -o %t.dir/index.plist %s \
|
||||||
|
// RUN: -analyzer-checker=core -analyzer-output=plist-html
|
||||||
|
//
|
||||||
// RUN: ls %t.dir | grep '\.html' | count 1
|
// RUN: ls %t.dir | grep '\.html' | count 1
|
||||||
// RUN: grep '\.html' %t.dir/index.plist | count 1
|
// RUN: grep '\.html' %t.dir/index.plist | count 1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue