[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:
Kristof Umann 2019-03-14 16:10:29 +00:00
parent ac093d61c4
commit 4962816e72
6 changed files with 69 additions and 2 deletions

View File

@ -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.

View File

@ -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"

View File

@ -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;
}

View File

@ -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

View File

@ -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}}
}

View File

@ -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