From a12643622ad3b85972dfdd80fe9006a3e8d8fb80 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 2 Apr 2013 00:26:15 +0000 Subject: [PATCH] [analyzer] Allow suppressing diagnostics reported within the 'std' namespace This is controlled by the 'suppress-c++-stdlib' analyzer-config flag. It is currently off by default. This is more suppression than we'd like to do, since obviously there can be user-caused issues within 'std', but it gives us the option to wield a large hammer to suppress false positives the user likely can't work around. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178513 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../StaticAnalyzer/Core/AnalyzerOptions.h | 10 +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 6 ++ .../Core/BugReporterVisitors.cpp | 39 ++++++++-- .../Inputs/system-header-simulator-cxx.h | 7 ++ .../diagnostics/explicit-suppression.cpp | 71 +++++++++++++++++++ 5 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 test/Analysis/diagnostics/explicit-suppression.cpp diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 5e29201447..b9f6f6cce1 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -217,6 +217,9 @@ private: /// \sa shouldSuppressInlinedDefensiveChecks Optional SuppressInlinedDefensiveChecks; + /// \sa shouldSuppressFromCXXStandardLibrary + Optional SuppressFromCXXStandardLibrary; + /// \sa getGraphTrimInterval Optional GraphTrimInterval; @@ -306,6 +309,13 @@ public: /// option, which accepts the values "true" and "false". bool shouldSuppressInlinedDefensiveChecks(); + /// Returns whether or not diagnostics reported within the C++ standard + /// library should be suppressed. + /// + /// This is controlled by the 'suppress-c++-stdlib' config option, + /// which accepts the values "true" and "false". + bool shouldSuppressFromCXXStandardLibrary(); + /// Returns whether irrelevant parts of a bug report path should be pruned /// out of the final output. /// diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 65faa10134..465f408e7f 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -158,6 +158,12 @@ bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() { /* Default = */ true); } +bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() { + return getBooleanOption(SuppressFromCXXStandardLibrary, + "suppress-c++-stdlib", + /* Default = */ false); +} + int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) { SmallString<10> StrBuf; llvm::raw_svector_ostream OS(StrBuf); diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 241388d18f..5f364304e8 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1421,28 +1421,53 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, return event; } + +// FIXME: Copied from ExprEngineCallAndReturn.cpp. +static bool isInStdNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext(); + const NamespaceDecl *ND = dyn_cast(DC); + if (!ND) + return false; + + while (const NamespaceDecl *Parent = dyn_cast(ND->getParent())) + ND = Parent; + + return ND->getName() == "std"; +} + + PathDiagnosticPiece * LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) { - const Stmt *S = BR.getStmt(); - if (!S) - return 0; - - // Here we suppress false positives coming from system macros. This list is + // Here we suppress false positives coming from system headers. This list is // based on known issues. + // Skip reports within the 'std' namespace. Although these can sometimes be + // the user's fault, we currently don't report them very well, and + // Note that this will not help for any other data structure libraries, like + // TR1, Boost, or llvm/ADT. + ExprEngine &Eng = BRC.getBugReporter().getEngine(); + AnalyzerOptions &Options = Eng.getAnalysisManager().options; + if (Options.shouldSuppressFromCXXStandardLibrary()) { + const LocationContext *LCtx = N->getLocationContext(); + if (isInStdNamespace(LCtx->getDecl())) { + BR.markInvalid(getTag(), 0); + return 0; + } + } + // Skip reports within the sys/queue.h macros as we do not have the ability to // reason about data structure shapes. SourceManager &SM = BRC.getSourceManager(); - SourceLocation Loc = S->getLocStart(); + FullSourceLoc Loc = BR.getLocation(SM).asLocation(); while (Loc.isMacroID()) { if (SM.isInSystemMacro(Loc) && (SM.getFilename(SM.getSpellingLoc(Loc)).endswith("sys/queue.h"))) { BR.markInvalid(getTag(), 0); return 0; } - Loc = SM.getSpellingLoc(Loc); + Loc = Loc.getSpellingLoc(); } return 0; diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h index 03de527a02..eee0e31a6f 100644 --- a/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -73,6 +73,13 @@ namespace std { struct nothrow_t {}; extern const nothrow_t nothrow; + + template + OutputIter copy(InputIter II, InputIter IE, OutputIter OI) { + while (II != IE) + *OI++ = *II++; + return OI; + } } void* operator new(std::size_t, const std::nothrow_t&) throw(); diff --git a/test/Analysis/diagnostics/explicit-suppression.cpp b/test/Analysis/diagnostics/explicit-suppression.cpp new file mode 100644 index 0000000000..6bc950f5d5 --- /dev/null +++ b/test/Analysis/diagnostics/explicit-suppression.cpp @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=false -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=true -DSUPPRESSED=1 -verify %s + +#ifdef SUPPRESSED +// expected-no-diagnostics +#endif + +#include "../Inputs/system-header-simulator-cxx.h" + +void clang_analyzer_eval(bool); + +void testCopyNull(int *I, int *E) { + std::copy(I, E, (int *)0); +#ifndef SUPPRESSED + // This line number comes from system-header-simulator-cxx.h. + // expected-warning@65 {{Dereference of null pointer}} +#endif +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// PR15613: expected-* can't refer to diagnostics in other source files. +// The current implementation only matches line numbers, but has an upper limit +// of the number of lines in the main source file. -- 2.40.0