From 1e715a66d7273e3b3203b13640c8ddce449acf03 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Sun, 16 Nov 2014 20:53:53 +0000 Subject: [PATCH] [Sanitizer] Parse and produce all sanitizer-relevant arguments in SanitizerArgs. In particular, make SanitizerArgs responsible for parsing and passing down to frontend -fsanitize-recover and -fsanitize-undefined-trap-on-error flags. Simplify parsing -f(no-)sanitize= flags parsing: get rid of too complex filterUnsupportedKinds function. No functionality change. llvm-svn: 222105 --- clang/include/clang/Driver/SanitizerArgs.h | 2 + clang/lib/Driver/SanitizerArgs.cpp | 113 ++++++++++++++++------------- clang/lib/Driver/Tools.cpp | 9 --- clang/test/Driver/fsanitize.c | 10 +-- 4 files changed, 68 insertions(+), 66 deletions(-) diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 01e3cb7..32b2e89 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -22,6 +22,8 @@ class ToolChain; class SanitizerArgs { SanitizerSet Sanitizers; + bool SanitizeRecover; + std::string BlacklistFile; int SanitizeCoverage; int MsanTrackOrigins; diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index d2b3a91..4460f9f 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -109,17 +109,32 @@ static std::string lastArgumentForKind(const Driver &D, /// "-fsanitize=alignment". static std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask); +/// Produce a string containing comma-separated names of sanitizers in \p +/// Sanitizers set. +static std::string toString(const clang::SanitizerSet &Sanitizers); + /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers /// this group enables. static unsigned expandGroups(unsigned Kinds); -/// Return the subset of \p Kinds supported by toolchain \p TC. If -/// \p DiagnoseErrors is true, produce an error diagnostic for each sanitizer -/// removed from \p Kinds. -static unsigned filterUnsupportedKinds(const ToolChain &TC, unsigned Kinds, - const llvm::opt::Arg *A, - bool DiagnoseErrors, - unsigned &DiagnosedKinds); +static unsigned getToolchainUnsupportedKinds(const ToolChain &TC) { + bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD; + bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; + bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; + bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; + + unsigned Unsupported = 0; + if (!(IsLinux && IsX86_64)) { + Unsupported |= Memory | DataFlow; + } + if (!((IsLinux || IsFreeBSD) && IsX86_64)) { + Unsupported |= Thread; + } + if (!(IsLinux && (IsX86 || IsX86_64))) { + Unsupported |= Function; + } + return Unsupported; +} bool SanitizerArgs::needsUbsanRt() const { return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt); @@ -135,6 +150,7 @@ bool SanitizerArgs::needsUnwindTables() const { void SanitizerArgs::clear() { Sanitizers.clear(); + SanitizeRecover = false; BlacklistFile = ""; SanitizeCoverage = 0; MsanTrackOrigins = 0; @@ -153,6 +169,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // argument or any argument after it. unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. // Used to deduplicate diagnostics. + unsigned Kinds = 0; + unsigned NotSupported = getToolchainUnsupportedKinds(TC); const Driver &D = TC.getDriver(); for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); I != E; ++I) { @@ -165,20 +183,31 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Avoid diagnosing any sanitizer which is disabled later. Add &= ~AllRemove; + // At this point we have not expanded groups, so any unsupported sanitizers // in Add are those which have been explicitly enabled. Diagnose them. - Add = filterUnsupportedKinds(TC, Add, *I, /*DiagnoseErrors=*/true, - DiagnosedKinds); + if (unsigned KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) { + // Only diagnose the new kinds. + std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); + D.Diag(diag::err_drv_unsupported_opt_for_target) << Desc + << TC.getTriple().str(); + DiagnosedKinds |= KindsToDiagnose; + } + Add &= ~NotSupported; + Add = expandGroups(Add); // Group expansion may have enabled a sanitizer which is disabled later. Add &= ~AllRemove; // Silently discard any unsupported sanitizers implicitly enabled through // group expansion. - Add = filterUnsupportedKinds(TC, Add, *I, /*DiagnoseErrors=*/false, - DiagnosedKinds); + Add &= ~NotSupported; - addAllOf(Sanitizers, Add); + Kinds |= Add; } + addAllOf(Sanitizers, Kinds); + + SanitizeRecover = Args.hasFlag(options::OPT_fsanitize_recover, + options::OPT_fno_sanitize_recover, true); UbsanTrapOnError = Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, @@ -316,17 +345,30 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); } +static std::string toString(const clang::SanitizerSet &Sanitizers) { + std::string Res; +#define SANITIZER(NAME, ID) \ + if (Sanitizers.has(clang::SanitizerKind::ID)) { \ + if (!Res.empty()) \ + Res += ","; \ + Res += NAME; \ + } +#include "clang/Basic/Sanitizers.def" + return Res; +} + void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { if (Sanitizers.empty()) return; - SmallString<256> SanitizeOpt("-fsanitize="); -#define SANITIZER(NAME, ID) \ - if (Sanitizers.has(SanitizerKind::ID)) \ - SanitizeOpt += NAME ","; -#include "clang/Basic/Sanitizers.def" - SanitizeOpt.pop_back(); - CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); + CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); + + if (!SanitizeRecover) + CmdArgs.push_back("-fno-sanitize-recover"); + + if (UbsanTrapOnError) + CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); + if (!BlacklistFile.empty()) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); BlacklistOpt += BlacklistFile; @@ -383,39 +425,6 @@ unsigned expandGroups(unsigned Kinds) { return Kinds; } -unsigned filterUnsupportedKinds(const ToolChain &TC, unsigned Kinds, - const llvm::opt::Arg *A, bool DiagnoseErrors, - unsigned &DiagnosedKinds) { - bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD; - bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; - bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; - bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; - - unsigned KindsToFilterOut = 0; - if (!(IsLinux && IsX86_64)) { - KindsToFilterOut |= Memory | DataFlow; - } - if (!((IsLinux || IsFreeBSD) && IsX86_64)) { - KindsToFilterOut |= Thread; - } - if (!(IsLinux && (IsX86 || IsX86_64))) { - KindsToFilterOut |= Function; - } - KindsToFilterOut &= Kinds; - - // Do we have new kinds to diagnose? - unsigned KindsToDiagnose = KindsToFilterOut & ~DiagnosedKinds; - if (DiagnoseErrors && KindsToDiagnose) { - // Only diagnose the new kinds. - std::string Desc = describeSanitizeArg(A, KindsToDiagnose); - TC.getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) - << Desc << TC.getTriple().str(); - DiagnosedKinds |= KindsToFilterOut; - } - - return Kinds & ~KindsToFilterOut; -} - unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors) { unsigned Kind = 0; diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 7b87f2e..b372b65 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -3625,15 +3625,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs(); Sanitize.addArgs(Args, CmdArgs); - if (!Args.hasFlag(options::OPT_fsanitize_recover, - options::OPT_fno_sanitize_recover, - true)) - CmdArgs.push_back("-fno-sanitize-recover"); - - if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, false)) - CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); - // Report an error for -faltivec on anything other than PowerPC. if (const Arg *A = Args.getLastArg(options::OPT_faltivec)) if (!(getToolChain().getArch() == llvm::Triple::ppc || diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index b01b3f0..c78dfc6 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -119,11 +119,11 @@ // RUN: %clang -target arm-linux-androideabi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ANDROID-NO-ASAN // CHECK-ANDROID-NO-ASAN: "-mrelocation-model" "pic" -// RUN: %clang -target x86_64-linux-gnu %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER -// RUN: %clang -target x86_64-linux-gnu %s -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER -// RUN: %clang -target x86_64-linux-gnu %s -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER -// RUN: %clang -target x86_64-linux-gnu %s -fno-sanitize-recover -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER -// RUN: %clang -target x86_64-linux-gnu %s -fsanitize-recover -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER +// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER +// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER +// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER +// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER +// RUZ: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER // CHECK-RECOVER-NOT: sanitize-recover // CHECK-NO-RECOVER: "-fno-sanitize-recover" -- 2.7.4