From a511cdd247777d947a2850d3e9c53d0bda19d6d5 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Wed, 4 Feb 2015 17:40:08 +0000 Subject: [PATCH] Allow to specify multiple -fsanitize-blacklist= arguments. Summary: Allow user to provide multiple blacklists by passing several -fsanitize-blacklist= options. These options now don't override default blacklist from Clang resource directory, which is always applied (which fixes PR22431). -fno-sanitize-blacklist option now disables all blacklists that were specified earlier in the command line (including the default one). This change depends on http://reviews.llvm.org/D7367. Test Plan: regression test suite Reviewers: timurrrr Subscribers: cfe-commits, kcc, pcc Differential Revision: http://reviews.llvm.org/D7368 llvm-svn: 228156 --- clang/include/clang/Basic/LangOptions.h | 5 ++- clang/include/clang/Basic/SanitizerBlacklist.h | 3 +- clang/include/clang/Driver/SanitizerArgs.h | 3 +- clang/lib/AST/ASTContext.cpp | 5 +-- clang/lib/Basic/LangOptions.cpp | 2 +- clang/lib/Basic/SanitizerBlacklist.cpp | 6 +-- clang/lib/CodeGen/BackendUtil.cpp | 2 +- clang/lib/Driver/SanitizerArgs.cpp | 52 ++++++++++++++------------ clang/lib/Frontend/CompilerInvocation.cpp | 2 +- clang/test/Driver/fsanitize-blacklist.c | 16 ++++++-- 10 files changed, 55 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index a021be1..8edfa4b 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -21,6 +21,7 @@ #include "clang/Basic/Sanitizers.h" #include "clang/Basic/Visibility.h" #include +#include namespace clang { @@ -70,9 +71,9 @@ public: /// \brief Set of enabled sanitizers. SanitizerSet Sanitize; - /// \brief Path to blacklist file specifying which objects + /// \brief Paths to blacklist files specifying which objects /// (files, functions, variables) should not be instrumented. - std::string SanitizerBlacklistFile; + std::vector SanitizerBlacklistFiles; clang::ObjCRuntime ObjCRuntime; diff --git a/clang/include/clang/Basic/SanitizerBlacklist.h b/clang/include/clang/Basic/SanitizerBlacklist.h index 2ce268a..e651e18 100644 --- a/clang/include/clang/Basic/SanitizerBlacklist.h +++ b/clang/include/clang/Basic/SanitizerBlacklist.h @@ -28,7 +28,8 @@ class SanitizerBlacklist { SourceManager &SM; public: - SanitizerBlacklist(StringRef BlacklistPath, SourceManager &SM); + SanitizerBlacklist(const std::vector &BlacklistPaths, + SourceManager &SM); bool isBlacklistedGlobal(StringRef GlobalName, StringRef Category = StringRef()) const; bool isBlacklistedType(StringRef MangledTypeName, diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 3524da0..c51fae3 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -13,6 +13,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include +#include namespace clang { namespace driver { @@ -24,7 +25,7 @@ class SanitizerArgs { SanitizerSet Sanitizers; SanitizerSet RecoverableSanitizers; - std::string BlacklistFile; + std::vector BlacklistFiles; int SanitizeCoverage; int MsanTrackOrigins; int AsanFieldPadding; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index d480277..68ae314 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -737,9 +737,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr), BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr), - FirstLocalImport(), LastLocalImport(), - SourceMgr(SM), LangOpts(LOpts), - SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFile, SM)), + FirstLocalImport(), LastLocalImport(), SourceMgr(SM), LangOpts(LOpts), + SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(nullptr), Listener(nullptr), diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index dcbd228..2c87845 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -30,7 +30,7 @@ void LangOptions::resetNonModularOptions() { // FIXME: This should not be reset; modules can be different with different // sanitizer options (this affects __has_feature(address_sanitizer) etc). Sanitize.clear(); - SanitizerBlacklistFile.clear(); + SanitizerBlacklistFiles.clear(); CurrentModule.clear(); ImplementationOfModule.clear(); diff --git a/clang/lib/Basic/SanitizerBlacklist.cpp b/clang/lib/Basic/SanitizerBlacklist.cpp index ea5b8d0..095fcd6 100644 --- a/clang/lib/Basic/SanitizerBlacklist.cpp +++ b/clang/lib/Basic/SanitizerBlacklist.cpp @@ -15,9 +15,9 @@ using namespace clang; -SanitizerBlacklist::SanitizerBlacklist(StringRef BlacklistPath, - SourceManager &SM) - : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPath)), SM(SM) {} +SanitizerBlacklist::SanitizerBlacklist( + const std::vector &BlacklistPaths, SourceManager &SM) + : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName, StringRef Category) const { diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index c4cea02..de57165 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -232,7 +232,7 @@ static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder, const PassManagerBuilderWrapper &BuilderWrapper = static_cast(Builder); const LangOptions &LangOpts = BuilderWrapper.getLangOpts(); - PM.add(createDataFlowSanitizerPass(LangOpts.SanitizerBlacklistFile)); + PM.add(createDataFlowSanitizerPass(LangOpts.SanitizerBlacklistFiles)); } static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple, diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 2740239..037fff2 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -151,7 +151,7 @@ bool SanitizerArgs::needsUnwindTables() const { void SanitizerArgs::clear() { Sanitizers.clear(); RecoverableSanitizers.clear(); - BlacklistFile = ""; + BlacklistFiles.clear(); SanitizeCoverage = 0; MsanTrackOrigins = 0; AsanFieldPadding = 0; @@ -285,30 +285,34 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // -f(-no)sanitize=leak should change whether leak detection is enabled by // default in ASan? + // Setup blacklist files. + // Add default blacklist from resource directory. + { + std::string BLPath; + if (getDefaultBlacklist(D, BLPath) && llvm::sys::fs::exists(BLPath)) + BlacklistFiles.push_back(BLPath); + } // Parse -f(no-)sanitize-blacklist options. - if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, - options::OPT_fno_sanitize_blacklist)) { - if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { - std::string BLPath = BLArg->getValue(); - if (llvm::sys::fs::exists(BLPath)) { - // Validate the blacklist format. - std::string BLError; - std::unique_ptr SCL( - llvm::SpecialCaseList::create(BLPath, BLError)); - if (!SCL.get()) - D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; - else - BlacklistFile = BLPath; - } else { + for (const auto *Arg : Args) { + if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { + Arg->claim(); + std::string BLPath = Arg->getValue(); + if (llvm::sys::fs::exists(BLPath)) + BlacklistFiles.push_back(BLPath); + else D.Diag(clang::diag::err_drv_no_such_file) << BLPath; - } + } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { + Arg->claim(); + BlacklistFiles.clear(); } - } else { - // If no -fsanitize-blacklist option is specified, try to look up for - // blacklist in the resource directory. - std::string BLPath; - if (getDefaultBlacklist(D, BLPath) && llvm::sys::fs::exists(BLPath)) - BlacklistFile = BLPath; + } + // Validate blacklists format. + { + std::string BLError; + std::unique_ptr SCL( + llvm::SpecialCaseList::create(BlacklistFiles, BLError)); + if (!SCL.get()) + D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; } // Parse -f[no-]sanitize-memory-track-origins[=level] options. @@ -405,9 +409,9 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, if (UbsanTrapOnError) CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); - if (!BlacklistFile.empty()) { + for (const auto &BLPath : BlacklistFiles) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); - BlacklistOpt += BlacklistFile; + BlacklistOpt += BLPath; CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 3b7fbb0..f8d71ac 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1669,7 +1669,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // -fsanitize-address-field-padding=N has to be a LangOpt, parse it here. Opts.SanitizeAddressFieldPadding = getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags); - Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist); + Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist); } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, diff --git a/clang/test/Driver/fsanitize-blacklist.c b/clang/test/Driver/fsanitize-blacklist.c index 690bc87..b63ac34 100644 --- a/clang/test/Driver/fsanitize-blacklist.c +++ b/clang/test/Driver/fsanitize-blacklist.c @@ -4,10 +4,12 @@ // REQUIRES: clang-driver, shell // RUN: echo "fun:foo" > %t.good +// RUN: echo "fun:bar" > %t.second // RUN: echo "badline" > %t.bad -// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BLACKLIST -// CHECK-BLACKLIST: -fsanitize-blacklist +// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.good -fsanitize-blacklist=%t.second %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BLACKLIST +// CHECK-BLACKLIST: -fsanitize-blacklist={{.*}}.good +// CHECK-BLACKLIST: -fsanitize-blacklist={{.*}}.second // Ignore -fsanitize-blacklist flag if there is no -fsanitize flag. // RUN: %clang -fsanitize-blacklist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SANITIZE @@ -22,5 +24,11 @@ // CHECK-NO-SUCH-FILE: error: no such file or directory: 'unexisting.txt' // Driver properly reports malformed blacklist files. -// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.bad %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BAD-BLACKLIST -// CHECK-BAD-BLACKLIST: error: malformed sanitizer blacklist +// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.second -fsanitize-blacklist=%t.bad -fsanitize-blacklist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BAD-BLACKLIST +// CHECK-BAD-BLACKLIST: error: malformed sanitizer blacklist: 'error parsing file '{{.*}}.bad': malformed line 1: 'badline'' + +// -fno-sanitize-blacklist disables all blacklists specified earlier. +// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.good -fno-sanitize-blacklist -fsanitize-blacklist=%t.second %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-FIRST-DISABLED +// CHECK-ONLY_FIRST-DISABLED-NOT: good +// CHECK-ONLY-FIRST-DISABLED: -fsanitize-blacklist={{.*}}.second +// CHECK-ONLY_FIRST-DISABLED-NOT: good -- 2.7.4