SanitizerArgs: add ability to filter/diagnose unsupported sanitizers.
The thread, memory, dataflow and function sanitizers are now diagnosed if
enabled explicitly on an unsupported platform. Unsupported sanitizers which
are enabled implicitly (as part of a larger group) are silently disabled. As a
side effect, this makes SanitizerArgs parsing toolchain-dependent (and thus
essentially reverts r188058), and moves SanitizerArgs ownership to ToolChain.
Differential Revision: http://llvm-reviews.chandlerc.com/D1990
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193875 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 4b13933..5307910 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -16,7 +16,6 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Options.h"
-#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/ArrayRef.h"
@@ -2056,10 +2055,3 @@
return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask);
}
-
-const SanitizerArgs &
-Driver::getOrParseSanitizerArgs(const ArgList &Args) const {
- if (!SanitizerArguments.get())
- SanitizerArguments.reset(new SanitizerArgs(*this, Args));
- return *SanitizerArguments.get();
-}
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index 8c9baa7..43209f0 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -25,7 +25,7 @@
Kind = 0;
BlacklistFile = "";
MsanTrackOrigins = false;
- AsanZeroBaseShadow = AZBSK_Default;
+ AsanZeroBaseShadow = false;
UbsanTrapOnError = false;
}
@@ -33,18 +33,42 @@
clear();
}
-SanitizerArgs::SanitizerArgs(const Driver &D, const llvm::opt::ArgList &Args) {
+SanitizerArgs::SanitizerArgs(const ToolChain &TC,
+ const llvm::opt::ArgList &Args) {
clear();
- unsigned AllKinds = 0; // All kinds of sanitizers that were turned on
- // at least once (possibly, disabled further).
- for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
+ unsigned AllAdd = 0; // All kinds of sanitizers that were turned on
+ // at least once (possibly, disabled further).
+ unsigned AllRemove = 0; // During the loop below, the accumulated set of
+ // sanitizers disabled by the current sanitizer
+ // argument or any argument after it.
+ unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
+ // Used to deduplicate diagnostics.
+ const Driver &D = TC.getDriver();
+ for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
+ I != E; ++I) {
unsigned Add, Remove;
if (!parse(D, Args, *I, Add, Remove, true))
continue;
(*I)->claim();
+
+ AllAdd |= expandGroups(Add);
+ AllRemove |= expandGroups(Remove);
+
+ // 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, Args, *I, /*DiagnoseErrors=*/true,
+ DiagnosedKinds);
+ 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, Args, *I, /*DiagnoseErrors=*/false,
+ DiagnosedKinds);
+
Kind |= Add;
- Kind &= ~Remove;
- AllKinds |= Add;
}
UbsanTrapOnError =
@@ -107,7 +131,7 @@
// If -fsanitize contains extra features of ASan, it should also
// explicitly contain -fsanitize=address (probably, turned off later in the
// command line).
- if ((Kind & AddressFull) != 0 && (AllKinds & Address) == 0)
+ if ((Kind & AddressFull) != 0 && (AllAdd & Address) == 0)
D.Diag(diag::warn_drv_unused_sanitizer)
<< lastArgumentForKind(D, Args, AddressFull)
<< "-fsanitize=address";
@@ -148,21 +172,25 @@
// Parse -f(no-)sanitize-address-zero-base-shadow options.
if (NeedsAsan) {
- if (Arg *A = Args.getLastArg(
- options::OPT_fsanitize_address_zero_base_shadow,
- options::OPT_fno_sanitize_address_zero_base_shadow))
- AsanZeroBaseShadow = A->getOption().matches(
- options::OPT_fsanitize_address_zero_base_shadow)
- ? AZBSK_On
- : AZBSK_Off;
+ bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android);
+ bool ZeroBaseShadowDefault = IsAndroid;
+ AsanZeroBaseShadow =
+ Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow,
+ options::OPT_fno_sanitize_address_zero_base_shadow,
+ ZeroBaseShadowDefault);
+ // Zero-base shadow is a requirement on Android.
+ if (IsAndroid && !AsanZeroBaseShadow) {
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fno-sanitize-address-zero-base-shadow"
+ << lastArgumentForKind(D, Args, Address);
+ }
}
}
-void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
+void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {
if (!Kind)
return;
- const Driver &D = TC.getDriver();
SmallString<256> SanitizeOpt("-fsanitize=");
#define SANITIZER(NAME, ID) \
if (Kind & ID) \
@@ -179,36 +207,19 @@
if (MsanTrackOrigins)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins"));
- if (needsAsanRt()) {
- if (hasAsanZeroBaseShadow(TC)) {
- CmdArgs.push_back(
- Args.MakeArgString("-fsanitize-address-zero-base-shadow"));
- } else if (TC.getTriple().getEnvironment() == llvm::Triple::Android) {
- // Zero-base shadow is a requirement on Android.
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fno-sanitize-address-zero-base-shadow"
- << lastArgumentForKind(D, Args, Address);
- }
- }
+ if (AsanZeroBaseShadow)
+ CmdArgs.push_back(
+ Args.MakeArgString("-fsanitize-address-zero-base-shadow"));
// Workaround for PR16386.
if (needsMsanRt())
CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
}
-bool SanitizerArgs::hasAsanZeroBaseShadow(const ToolChain &TC) const {
- if (!needsAsanRt())
- return false;
- if (AsanZeroBaseShadow != AZBSK_Default)
- return AsanZeroBaseShadow == AZBSK_On;
- // Zero-base shadow is used by default only on Android.
- return TC.getTriple().getEnvironment() == llvm::Triple::Android;
-}
-
unsigned SanitizerArgs::parse(const char *Value) {
unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
#define SANITIZER(NAME, ID) .Case(NAME, ID)
-#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID)
+#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
#include "clang/Basic/Sanitizers.def"
.Default(SanitizeKind());
// Assume -fsanitize=address implies -fsanitize=init-order,use-after-return.
@@ -219,6 +230,54 @@
return ParsedKind;
}
+unsigned SanitizerArgs::expandGroups(unsigned Kinds) {
+#define SANITIZER(NAME, ID)
+#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
+#include "clang/Basic/Sanitizers.def"
+ return Kinds;
+}
+
+void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
+ unsigned Mask,
+ const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ bool DiagnoseErrors,
+ unsigned &DiagnosedKinds) {
+ unsigned MaskedKinds = Kinds & Mask;
+ if (!MaskedKinds)
+ return;
+ Kinds &= ~Mask;
+ // Do we have new kinds to diagnose?
+ if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) {
+ // Only diagnose the new kinds.
+ std::string Desc =
+ describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds);
+ TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << Desc << TC.getTriple().str();
+ DiagnosedKinds |= MaskedKinds;
+ }
+}
+
+unsigned SanitizerArgs::filterUnsupportedKinds(const ToolChain &TC,
+ unsigned Kinds,
+ const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ bool DiagnoseErrors,
+ unsigned &DiagnosedKinds) {
+ 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;
+ if (!(IsLinux && IsX86_64)) {
+ filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A,
+ DiagnoseErrors, DiagnosedKinds);
+ }
+ if (!(IsLinux && (IsX86 || IsX86_64))) {
+ filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors,
+ DiagnosedKinds);
+ }
+ return Kinds;
+}
+
unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors) {
unsigned Kind = 0;
@@ -282,7 +341,7 @@
I != E; ++I) {
unsigned Add, Remove;
if (parse(D, Args, *I, Add, Remove, false) &&
- (Add & Kind))
+ (expandGroups(Add) & Kind))
return describeSanitizeArg(Args, *I, Kind);
Kind &= ~Remove;
}
@@ -295,11 +354,17 @@
if (!A->getOption().matches(options::OPT_fsanitize_EQ))
return A->getAsString(Args);
- for (unsigned I = 0, N = A->getNumValues(); I != N; ++I)
- if (parse(A->getValue(I)) & Mask)
- return std::string("-fsanitize=") + A->getValue(I);
+ std::string Sanitizers;
+ for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
+ if (expandGroups(parse(A->getValue(I))) & Mask) {
+ if (!Sanitizers.empty())
+ Sanitizers += ",";
+ Sanitizers += A->getValue(I);
+ }
+ }
- llvm_unreachable("arg didn't provide expected value");
+ assert(!Sanitizers.empty() && "arg didn't provide expected value");
+ return "-fsanitize=" + Sanitizers;
}
bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index e21dd06..9fe0379 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
@@ -43,7 +44,9 @@
}
const SanitizerArgs& ToolChain::getSanitizerArgs() const {
- return D.getOrParseSanitizerArgs(Args);
+ if (!SanitizerArguments.get())
+ SanitizerArguments.reset(new SanitizerArgs(*this, Args));
+ return *SanitizerArguments.get();
}
std::string ToolChain::getDefaultUniversalArchName() const {
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 2a112c2..99a182e 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -300,10 +300,11 @@
}
}
- const SanitizerArgs &Sanitize = getDriver().getOrParseSanitizerArgs(Args);
+ const SanitizerArgs &Sanitize = getSanitizerArgs();
// Add Ubsan runtime library, if required.
if (Sanitize.needsUbsanRt()) {
+ // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
if (isTargetIPhoneOS()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=undefined";
@@ -318,6 +319,7 @@
// Add ASAN runtime library, if required. Dynamic libraries and bundles
// should not be linked with the runtime library.
if (Sanitize.needsAsanRt()) {
+ // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
if (isTargetIPhoneOS() && !isTargetIOSSimulator()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=address";
@@ -2722,7 +2724,7 @@
}
bool Linux::isPIEDefault() const {
- return getSanitizerArgs().hasZeroBaseShadow(*this);
+ return getSanitizerArgs().hasZeroBaseShadow();
}
/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 646fb61..3c821b6 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -2942,8 +2942,8 @@
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
- const SanitizerArgs &Sanitize = D.getOrParseSanitizerArgs(Args);
- Sanitize.addArgs(getToolChain(), Args, CmdArgs);
+ const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs();
+ Sanitize.addArgs(Args, CmdArgs);
if (!Args.hasFlag(options::OPT_fsanitize_recover,
options::OPT_fno_sanitize_recover,
@@ -6188,10 +6188,10 @@
const Driver &D = ToolChain.getDriver();
const bool isAndroid =
ToolChain.getTriple().getEnvironment() == llvm::Triple::Android;
- const SanitizerArgs &Sanitize = D.getOrParseSanitizerArgs(Args);
+ const SanitizerArgs &Sanitize = ToolChain.getSanitizerArgs();
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
- (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow(ToolChain));
+ (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow());
ArgStringList CmdArgs;
@@ -6722,7 +6722,7 @@
ImplibName.str()));
}
- if (getToolChain().getDriver().getOrParseSanitizerArgs(Args).needsAsanRt()) {
+ if (getToolChain().getSanitizerArgs().needsAsanRt()) {
CmdArgs.push_back(Args.MakeArgString("-debug"));
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
SmallString<128> LibSanitizer(getToolChain().getDriver().ResourceDir);