Skip to content

Commit

Permalink
[analyzer] Do not analyze bison-generated files
Browse files Browse the repository at this point in the history
Bison/YACC generated files result in a very large number of (presumably)
false positives from the analyzer.
These false positives are "true" in a sense of the information analyzer
sees: assuming that the lexer can return any token at any point a number
of uninitialized reads does occur.
(naturally, the analyzer can not capture a complex invariant that
certain tokens can only occur under certain conditions).

Current fix simply stops analysis on those files.
I have examined a very large number of such auto-generated files, and
they do all start with such a comment.
Conversely, user code is very unlikely to contain such a comment.

rdar://33608161

Differential Revision: https://reviews.llvm.org/D43421

llvm-svn: 326135
  • Loading branch information
George Karpenkov committed Feb 26, 2018
1 parent 24f9794 commit 1d3e49e
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 37 deletions.
98 changes: 61 additions & 37 deletions clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
Expand Up @@ -389,7 +389,10 @@ class AnalysisConsumer : public AnalysisASTConsumer,

/// \brief Check if we should skip (not analyze) the given function.
AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
void runAnalysisOnTranslationUnit(ASTContext &C);

/// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set.
void reportAnalyzerProgress(StringRef S);
};
} // end anonymous namespace

Expand Down Expand Up @@ -511,51 +514,72 @@ void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
}
}

static bool isBisonFile(ASTContext &C) {
const SourceManager &SM = C.getSourceManager();
FileID FID = SM.getMainFileID();
StringRef Buffer = SM.getBuffer(FID)->getBuffer();
if (Buffer.startswith("/* A Bison parser, made by"))
return true;
return false;
}

void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {
BugReporter BR(*Mgr);
TranslationUnitDecl *TU = C.getTranslationUnitDecl();
checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);

// Run the AST-only checks using the order in which functions are defined.
// If inlining is not turned on, use the simplest function order for path
// sensitive analyzes as well.
RecVisitorMode = AM_Syntax;
if (!Mgr->shouldInlineCall())
RecVisitorMode |= AM_Path;
RecVisitorBR = &BR;

// Process all the top level declarations.
//
// Note: TraverseDecl may modify LocalTUDecls, but only by appending more
// entries. Thus we don't use an iterator, but rely on LocalTUDecls
// random access. By doing so, we automatically compensate for iterators
// possibly being invalidated, although this is a bit slower.
const unsigned LocalTUDeclsSize = LocalTUDecls.size();
for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
TraverseDecl(LocalTUDecls[i]);
}

if (Mgr->shouldInlineCall())
HandleDeclsCallGraph(LocalTUDeclsSize);

// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);

RecVisitorBR = nullptr;
}

void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
if (Opts->AnalyzerDisplayProgress)
llvm::errs() << S;
}

void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {

// Don't run the actions if an error has occurred with parsing the file.
DiagnosticsEngine &Diags = PP.getDiagnostics();
if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;

// Don't analyze if the user explicitly asked for no checks to be performed
// on this file.
if (Opts->DisableAllChecks)
return;

{
if (TUTotalTimer) TUTotalTimer->startTimer();

// Introduce a scope to destroy BR before Mgr.
BugReporter BR(*Mgr);
TranslationUnitDecl *TU = C.getTranslationUnitDecl();
checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);

// Run the AST-only checks using the order in which functions are defined.
// If inlining is not turned on, use the simplest function order for path
// sensitive analyzes as well.
RecVisitorMode = AM_Syntax;
if (!Mgr->shouldInlineCall())
RecVisitorMode |= AM_Path;
RecVisitorBR = &BR;

// Process all the top level declarations.
//
// Note: TraverseDecl may modify LocalTUDecls, but only by appending more
// entries. Thus we don't use an iterator, but rely on LocalTUDecls
// random access. By doing so, we automatically compensate for iterators
// possibly being invalidated, although this is a bit slower.
const unsigned LocalTUDeclsSize = LocalTUDecls.size();
for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
TraverseDecl(LocalTUDecls[i]);
}

if (Mgr->shouldInlineCall())
HandleDeclsCallGraph(LocalTUDeclsSize);
if (TUTotalTimer) TUTotalTimer->startTimer();

// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
if (isBisonFile(C)) {
reportAnalyzerProgress("Skipping bison-generated file\n");
} else if (Opts->DisableAllChecks) {

RecVisitorBR = nullptr;
// Don't analyze if the user explicitly asked for no checks to be performed
// on this file.
reportAnalyzerProgress("All checks are disabled using a supplied option\n");
} else {
// Otherwise, just run the analysis.
runAnalysisOnTranslationUnit(C);
}

if (TUTotalTimer) TUTotalTimer->stopTimer();
Expand Down
13 changes: 13 additions & 0 deletions clang/test/Analysis/yaccignore.c
@@ -0,0 +1,13 @@
/* A Bison parser, made by GNU Bison 1.875. */

// RUN: rm -rf %t.plist
// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist -o %t.plist -verify %s
// RUN: FileCheck --input-file=%t.plist %s

// expected-no-diagnostics
int foo() {
int *x = 0;
return *x; // no-warning
}

// CHECK: <key>diagnostics</key>

0 comments on commit 1d3e49e

Please sign in to comment.