diff options
author | Kristof Umann <kristof.umann@ericsson.com> | 2019-05-17 09:51:59 +0000 |
---|---|---|
committer | Kristof Umann <kristof.umann@ericsson.com> | 2019-05-17 09:51:59 +0000 |
commit | 85cf76e783a4bbd821c9673feec6995ed909dda9 (patch) | |
tree | 9fa95c9d46c2fd58cfbdc2fc02ac57856ff435c4 /clang/lib/StaticAnalyzer/Frontend | |
parent | 62370dd0e048551aeb26d960d7d817dd2bf7f18c (diff) | |
download | bcm5719-llvm-85cf76e783a4bbd821c9673feec6995ed909dda9.tar.gz bcm5719-llvm-85cf76e783a4bbd821c9673feec6995ed909dda9.zip |
[analyzer] Validate checker option names and values
Validate whether the option exists, and also whether the supplied value is of
the correct type. With this patch, invoking the analyzer should be, at least
in the frontend mode, a lot safer.
Differential Revision: https://reviews.llvm.org/D57860
llvm-svn: 361011
Diffstat (limited to 'clang/lib/StaticAnalyzer/Frontend')
-rw-r--r-- | clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp | 119 |
1 files changed, 101 insertions, 18 deletions
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index 7eef09b8833..437e4aaf1a2 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -9,6 +9,7 @@ #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LLVM.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" @@ -306,18 +307,61 @@ void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { Dependencies.emplace_back(FullName, Dependency); } +/// Insert the checker/package option to AnalyzerOptions' config table, and +/// validate it, if the user supplied it on the command line. +static void insertAndValidate(StringRef FullName, + const CheckerRegistry::CmdLineOption &Option, + AnalyzerOptions &AnOpts, + DiagnosticsEngine &Diags) { + + std::string FullOption = (FullName + ":" + Option.OptionName).str(); + + auto It = AnOpts.Config.insert({FullOption, Option.DefaultValStr}); + + // Insertation was successful -- CmdLineOption's constructor will validate + // whether values received from plugins or TableGen files are correct. + if (It.second) + return; + + // Insertion failed, the user supplied this package/checker option on the + // command line. If the supplied value is invalid, we'll emit an error. + + StringRef SuppliedValue = It.first->getValue(); + + if (Option.OptionType == "bool") { + if (SuppliedValue != "true" && SuppliedValue != "false") { + if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { + Diags.Report(diag::err_analyzer_checker_option_invalid_input) + << FullOption << "a boolean value"; + } + } + return; + } + + if (Option.OptionType == "int") { + int Tmp; + bool HasFailed = SuppliedValue.getAsInteger(0, Tmp); + if (HasFailed) { + if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { + Diags.Report(diag::err_analyzer_checker_option_invalid_input) + << FullOption << "an integer value"; + } + } + return; + } +} + template <class T> static void insertOptionToCollection(StringRef FullName, T &Collection, const CheckerRegistry::CmdLineOption &Option, - AnalyzerOptions &AnOpts) { + AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) { auto It = binaryFind(Collection, FullName); assert(It != Collection.end() && "Failed to find the checker while attempting to add a command line " "option to it!"); - AnOpts.Config.insert( - {(FullName + ":" + Option.OptionName).str(), Option.DefaultValStr}); + insertAndValidate(FullName, Option, AnOpts, Diags); It->CmdLineOptions.emplace_back(Option); } @@ -326,14 +370,14 @@ void CheckerRegistry::resolveCheckerAndPackageOptions() { for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry : CheckerOptions) { insertOptionToCollection(CheckerOptEntry.first, Checkers, - CheckerOptEntry.second, AnOpts); + CheckerOptEntry.second, AnOpts, Diags); } CheckerOptions.clear(); for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry : PackageOptions) { - insertOptionToCollection(PackageOptEntry.first, Checkers, - PackageOptEntry.second, AnOpts); + insertOptionToCollection(PackageOptEntry.first, Packages, + PackageOptEntry.second, AnOpts, Diags); } PackageOptions.clear(); } @@ -388,23 +432,62 @@ void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { } } +static void +isOptionContainedIn(const CheckerRegistry::CmdLineOptionList &OptionList, + StringRef SuppliedChecker, StringRef SuppliedOption, + const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) { + + if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue) + return; + + using CmdLineOption = CheckerRegistry::CmdLineOption; + + auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) { + return Opt.OptionName == SuppliedOption; + }; + + auto OptionIt = llvm::find_if(OptionList, SameOptName); + + if (OptionIt == OptionList.end()) { + Diags.Report(diag::err_analyzer_checker_option_unknown) + << SuppliedChecker << SuppliedOption; + return; + } +} + void CheckerRegistry::validateCheckerOptions() const { for (const auto &Config : AnOpts.Config) { - size_t Pos = Config.getKey().find(':'); - if (Pos == StringRef::npos) + + StringRef SuppliedChecker; + StringRef SuppliedOption; + std::tie(SuppliedChecker, SuppliedOption) = Config.getKey().split(':'); + + if (SuppliedOption.empty()) continue; - bool HasChecker = false; - StringRef CheckerName = Config.getKey().substr(0, Pos); - for (const auto &Checker : Checkers) { - if (Checker.FullName.startswith(CheckerName) && - (Checker.FullName.size() == Pos || Checker.FullName[Pos] == '.')) { - HasChecker = true; - break; - } + // AnalyzerOptions' config table contains the user input, so an entry could + // look like this: + // + // cor:NoFalsePositives=true + // + // Since lower_bound would look for the first element *not less* than "cor", + // it would return with an iterator to the first checker in the core, so we + // we really have to use find here, which uses operator==. + auto CheckerIt = llvm::find(Checkers, CheckerInfo(SuppliedChecker)); + if (CheckerIt != Checkers.end()) { + isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedChecker, + SuppliedOption, AnOpts, Diags); + continue; } - if (!HasChecker) - Diags.Report(diag::err_unknown_analyzer_checker) << CheckerName; + + auto PackageIt = llvm::find(Packages, PackageInfo(SuppliedChecker)); + if (PackageIt != Packages.end()) { + isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedChecker, + SuppliedOption, AnOpts, Diags); + continue; + } + + Diags.Report(diag::err_unknown_analyzer_checker) << SuppliedChecker; } } |