Index: include/clang/CodeGen/BackendUtil.h =================================================================== --- include/clang/CodeGen/BackendUtil.h +++ include/clang/CodeGen/BackendUtil.h @@ -11,9 +11,11 @@ #define LLVM_CLANG_CODEGEN_BACKEND_UTIL_H #include "clang/Basic/LLVM.h" +#include namespace llvm { class Module; + class SpecialCaseList; } namespace clang { @@ -31,6 +33,9 @@ Backend_EmitObj ///< Emit native object files }; + std::unique_ptr + CreateSpecialCaseList(const CodeGenOptions &CGOpts); + void EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts, const TargetOptions &TOpts, const LangOptions &LOpts, StringRef TDesc, llvm::Module *M, BackendAction Action, Index: include/clang/Driver/SanitizerArgs.h =================================================================== --- include/clang/Driver/SanitizerArgs.h +++ include/clang/Driver/SanitizerArgs.h @@ -9,6 +9,7 @@ #ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_ #define CLANG_LIB_DRIVER_SANITIZERARGS_H_ +#include "clang/Basic/LLVM.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include @@ -47,7 +48,7 @@ }; unsigned Kind; - std::string BlacklistFile; + std::vector BlacklistFiles; int MsanTrackOrigins; bool AsanZeroBaseShadow; bool UbsanTrapOnError; @@ -83,6 +84,8 @@ private: void clear(); + void addBlacklistFile(const Driver &D, StringRef Path); + /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0 /// if \p Value is not known. Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -134,8 +134,8 @@ /// The name of the relocation model to use. std::string RelocationModel; - /// Path to blacklist file for sanitizers. - std::string SanitizerBlacklistFile; + /// Paths to blacklist files for sanitizers. + std::vector SanitizerBlacklistFiles; /// If not an empty string, trap intrinsics are lowered to calls to this /// function instead of to trap instructions. Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -18,6 +18,7 @@ #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/SchedulerRegistry.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/Module.h" @@ -27,6 +28,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/SpecialCaseList.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" @@ -215,7 +217,7 @@ const PassManagerBuilderWrapper &BuilderWrapper = static_cast(Builder); const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); - PM.add(createDataFlowSanitizerPass(CGOpts.SanitizerBlacklistFile)); + PM.add(createDataFlowSanitizerPass(CreateSpecialCaseList(CGOpts))); } void EmitAssemblyHelper::CreatePasses() { @@ -588,6 +590,18 @@ } } +std::unique_ptr clang::CreateSpecialCaseList(const CodeGenOptions &CGOpts) { + auto SCL = llvm::make_unique(); + for (const auto &Path : CGOpts.SanitizerBlacklistFiles) { + std::string Error; + if (!SCL->loadFromFile(Path, Error)) { + report_fatal_error(Error); + } + } + + return SCL; +} + void clang::EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts, const clang::TargetOptions &TOpts, Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -39,6 +39,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/CodeGen/BackendUtil.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/APSInt.h" @@ -89,8 +90,7 @@ NSConcreteStackBlock(nullptr), BlockObjectAssign(nullptr), BlockObjectDispose(nullptr), BlockDescriptorType(nullptr), GenericBlockLiteralType(nullptr), LifetimeStartFn(nullptr), - LifetimeEndFn(nullptr), SanitizerBL(llvm::SpecialCaseList::createOrDie( - CGO.SanitizerBlacklistFile)), + LifetimeEndFn(nullptr), SanitizerBL(CreateSpecialCaseList(CGO)), SanitizerMD(new SanitizerMetadata(*this)) { // Initialize the type cache. Index: lib/CodeGen/SanitizerBlacklist.h =================================================================== --- lib/CodeGen/SanitizerBlacklist.h +++ lib/CodeGen/SanitizerBlacklist.h @@ -32,7 +32,8 @@ std::unique_ptr SCL; public: - SanitizerBlacklist(llvm::SpecialCaseList *SCL) : SCL(SCL) {} + SanitizerBlacklist(std::unique_ptr SCL) + : SCL(std::move(SCL)) {} bool isIn(const llvm::Module &M, const StringRef Category = StringRef()) const; bool isIn(const llvm::Function &F) const; Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -23,7 +23,7 @@ void SanitizerArgs::clear() { Kind = 0; - BlacklistFile = ""; + BlacklistFiles.clear(); MsanTrackOrigins = 0; AsanZeroBaseShadow = false; UbsanTrapOnError = false; @@ -113,31 +113,22 @@ // -f(-no)sanitize=leak should change whether leak detection is enabled by // default in ASan? - // 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(diag::err_drv_malformed_sanitizer_blacklist) << BLError; - else - BlacklistFile = BLPath; - } else { - D.Diag(diag::err_drv_no_such_file) << BLPath; - } - } - } else { - // If no -fsanitize-blacklist option is specified, try to look up for - // blacklist in the resource directory. + // If -fno-sanitize-blacklist option is not specified, try to look up the + // blacklist in the resource directory. + if (!Args.hasArg(options::OPT_fno_sanitize_blacklist)) { std::string BLPath; if (getDefaultBlacklistForKind(D, Kind, BLPath) && llvm::sys::fs::exists(BLPath)) - BlacklistFile = BLPath; + addBlacklistFile(D, BLPath); + } + + // Parse -fsanitize-blacklist options. + for (auto Arg : Args.filtered(options::OPT_fsanitize_blacklist)) { + Arg->claim(); + if (llvm::sys::fs::exists(Arg->getValue())) + addBlacklistFile(D, Arg->getValue()); + else + D.Diag(diag::err_drv_no_such_file) << Arg->getValue(); } // Parse -f[no-]sanitize-memory-track-origins[=level] options. @@ -170,6 +161,16 @@ } } +void SanitizerArgs::addBlacklistFile(const Driver &D, StringRef BLPath) { + // Validate the blacklist format. + std::string BLError; + llvm::SpecialCaseList SCL; + if (!SCL.loadFromFile(BLPath, BLError)) + D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError; + else + BlacklistFiles.push_back(BLPath); +} + void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { if (!Kind) @@ -181,9 +182,9 @@ #include "clang/Basic/Sanitizers.def" SanitizeOpt.pop_back(); CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); - if (!BlacklistFile.empty()) { + for (const auto &File : BlacklistFiles) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); - BlacklistOpt += BlacklistFile; + BlacklistOpt += File; CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -482,7 +482,7 @@ Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file); - Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist); + Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); Opts.SanitizeUndefinedTrapOnError = Index: test/CodeGen/address-safety-attr.cpp =================================================================== --- test/CodeGen/address-safety-attr.cpp +++ test/CodeGen/address-safety-attr.cpp @@ -1,9 +1,11 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix=ASAN %s // RUN: echo "src:%s" > %t.file.blacklist -// RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist +// RUN: echo "fun:*BlacklistedFunction1*" > %t.func1.blacklist +// RUN: echo "fun:*BlacklistedFunction2*" > %t.func2.blacklist // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s -// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.func1.blacklist | FileCheck -check-prefix=BLFUNC %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.func1.blacklist -fsanitize-blacklist=%t.func2.blacklist | FileCheck -check-prefix=BLFUNC12 %s // FIXME: %t.file.blacklist is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp" // REQUIRES: shell @@ -15,6 +17,7 @@ // WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] // BLFILE: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] // BLFUNC: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] +// BLFUNC12: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] // ASAN: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] __attribute__((no_sanitize_address)) int NoAddressSafety1(int *a) { return *a; } @@ -22,6 +25,7 @@ // WITHOUT: NoAddressSafety2{{.*}}) [[NOATTR]] // BLFILE: NoAddressSafety2{{.*}}) [[NOATTR]] // BLFUNC: NoAddressSafety2{{.*}}) [[NOATTR]] +// BLFUNC12: NoAddressSafety2{{.*}}) [[NOATTR]] // ASAN: NoAddressSafety2{{.*}}) [[NOATTR]] __attribute__((no_sanitize_address)) int NoAddressSafety2(int *a); @@ -30,18 +34,28 @@ // WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]] // BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]] // BLFUNC: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]] +// BLFUNC12: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]] // ASAN: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]] int AddressSafetyOk(int *a) { return *a; } -// WITHOUT: BlacklistedFunction{{.*}}) [[NOATTR]] -// BLFILE: BlacklistedFunction{{.*}}) [[NOATTR]] -// BLFUNC: BlacklistedFunction{{.*}}) [[NOATTR]] -// ASAN: BlacklistedFunction{{.*}}) [[WITH]] -int BlacklistedFunction(int *a) { return *a; } +// WITHOUT: BlacklistedFunction1{{.*}}) [[NOATTR]] +// BLFILE: BlacklistedFunction1{{.*}}) [[NOATTR]] +// BLFUNC: BlacklistedFunction1{{.*}}) [[NOATTR]] +// BLFUNC12: BlacklistedFunction1{{.*}}) [[NOATTR]] +// ASAN: BlacklistedFunction1{{.*}}) [[WITH]] +int BlacklistedFunction1(int *a) { return *a; } + +// WITHOUT: BlacklistedFunction2{{.*}}) [[NOATTR]] +// BLFILE: BlacklistedFunction2{{.*}}) [[NOATTR]] +// BLFUNC: BlacklistedFunction2{{.*}}) [[WITH]] +// BLFUNC12: BlacklistedFunction2{{.*}}) [[NOATTR]] +// ASAN: BlacklistedFunction2{{.*}}) [[WITH]] +int BlacklistedFunction2(int *a) { return *a; } // WITHOUT: TemplateAddressSafetyOk{{.*}}) [[NOATTR]] // BLFILE: TemplateAddressSafetyOk{{.*}}) [[NOATTR]] // BLFUNC: TemplateAddressSafetyOk{{.*}}) [[WITH]] +// BLFUNC12: TemplateAddressSafetyOk{{.*}}) [[WITH]] // ASAN: TemplateAddressSafetyOk{{.*}}) [[WITH]] template int TemplateAddressSafetyOk() { return i; } @@ -49,6 +63,7 @@ // WITHOUT: TemplateNoAddressSafety{{.*}}) [[NOATTR]] // BLFILE: TemplateNoAddressSafety{{.*}}) [[NOATTR]] // BLFUNC: TemplateNoAddressSafety{{.*}}) [[NOATTR]] +// BLFUNC12: TemplateNoAddressSafety{{.*}}) [[NOATTR]] // ASAN: TemplateNoAddressSafety{{.*}}) [[NOATTR]] template __attribute__((no_sanitize_address)) @@ -63,6 +78,7 @@ // WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]] // BLFILE: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]] // BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]] +// BLFUNC12: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]] // ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]] // WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} } @@ -75,6 +91,10 @@ // BLFUNC: attributes [[WITH]] = { nounwind sanitize_address{{.*}} } // BLFUNC: attributes [[WITH_NO_TF]] = { nounwind sanitize_address } +// BLFUNC12: attributes [[NOATTR]] = { nounwind{{.*}} } +// BLFUNC12: attributes [[WITH]] = { nounwind sanitize_address{{.*}} } +// BLFUNC12: attributes [[WITH_NO_TF]] = { nounwind sanitize_address } + // ASAN: attributes [[NOATTR]] = { nounwind{{.*}} } // ASAN: attributes [[WITH]] = { nounwind sanitize_address{{.*}} } // ASAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_address } Index: test/Driver/fsanitize-blacklist.c =================================================================== --- test/Driver/fsanitize-blacklist.c +++ test/Driver/fsanitize-blacklist.c @@ -13,14 +13,10 @@ // RUN: %clang -fsanitize-blacklist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SANITIZE // CHECK-NO-SANITIZE-NOT: -fsanitize-blacklist -// Flag -fno-sanitize-blacklist wins if it is specified later. -// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.good -fno-sanitize-blacklist %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-BLACKLIST -// CHECK-NO-BLACKLIST-NOT: -fsanitize-blacklist - // Driver barks on unexisting blacklist files. // RUN: %clang -fno-sanitize-blacklist -fsanitize-blacklist=unexisting.txt %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SUCH-FILE // 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 +// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.good -fsanitize-blacklist=%t.bad %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BAD-BLACKLIST // CHECK-BAD-BLACKLIST: error: malformed sanitizer blacklist