summaryrefslogtreecommitdiffstats
path: root/lib/Driver/SanitizerArgs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Driver/SanitizerArgs.cpp')
-rw-r--r--lib/Driver/SanitizerArgs.cpp138
1 files changed, 92 insertions, 46 deletions
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index 72530b4..14c3702 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -25,7 +25,7 @@ using namespace clang::driver;
using namespace llvm::opt;
enum : SanitizerMask {
- NeedsUbsanRt = Undefined | Integer,
+ NeedsUbsanRt = Undefined | Integer | CFI,
NotAllowedWithTrap = Vptr,
RequiresPIE = Memory | DataFlow,
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
@@ -34,6 +34,9 @@ enum : SanitizerMask {
Unrecoverable = Address | Unreachable | Return,
LegacyFsanitizeRecoverMask = Undefined | Integer,
NeedsLTO = CFI,
+ TrappingSupported =
+ (Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
+ TrappingDefault = CFI,
};
enum CoverageFeature {
@@ -74,27 +77,6 @@ static std::string describeSanitizeArg(const llvm::opt::Arg *A,
/// Sanitizers set.
static std::string toString(const clang::SanitizerSet &Sanitizers);
-static SanitizerMask 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;
- bool IsMIPS64 = TC.getTriple().getArch() == llvm::Triple::mips64 ||
- TC.getTriple().getArch() == llvm::Triple::mips64el;
-
- SanitizerMask Unsupported = 0;
- if (!(IsLinux && (IsX86_64 || IsMIPS64))) {
- Unsupported |= Memory | DataFlow;
- }
- if (!((IsLinux || IsFreeBSD) && (IsX86_64 || IsMIPS64))) {
- Unsupported |= Thread;
- }
- if (!(IsLinux && (IsX86 || IsX86_64))) {
- Unsupported |= Function;
- }
- return Unsupported;
-}
-
static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
std::string &BLPath) {
const char *BlacklistFile = nullptr;
@@ -116,8 +98,62 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
return false;
}
+/// Sets group bits for every group that has at least one representative already
+/// enabled in \p Kinds.
+static SanitizerMask setGroupBits(SanitizerMask Kinds) {
+#define SANITIZER(NAME, ID)
+#define SANITIZER_GROUP(NAME, ID, ALIAS) \
+ if (Kinds & SanitizerKind::ID) \
+ Kinds |= SanitizerKind::ID##Group;
+#include "clang/Basic/Sanitizers.def"
+ return Kinds;
+}
+
+static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
+ const llvm::opt::ArgList &Args) {
+ SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of
+ // sanitizers disabled by the current sanitizer
+ // argument or any argument after it.
+ SanitizerMask TrappingKinds = 0;
+ SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported);
+
+ for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
+ I != E; ++I) {
+ const auto *Arg = *I;
+ if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
+ Arg->claim();
+ SanitizerMask Add = parseArgValues(D, Arg, true);
+ Add &= ~TrapRemove;
+ if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
+ SanitizerSet S;
+ S.Mask = InvalidValues;
+ D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap"
+ << toString(S);
+ }
+ TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove;
+ } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
+ Arg->claim();
+ TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true));
+ } else if (Arg->getOption().matches(
+ options::OPT_fsanitize_undefined_trap_on_error)) {
+ Arg->claim();
+ TrappingKinds |=
+ expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove;
+ } else if (Arg->getOption().matches(
+ options::OPT_fno_sanitize_undefined_trap_on_error)) {
+ Arg->claim();
+ TrapRemove |= expandSanitizerGroups(UndefinedGroup);
+ }
+ }
+
+ // Apply default trapping behavior.
+ TrappingKinds |= TrappingDefault & ~TrapRemove;
+
+ return TrappingKinds;
+}
+
bool SanitizerArgs::needsUbsanRt() const {
- return !UbsanTrapOnError && (Sanitizers.Mask & NeedsUbsanRt) &&
+ return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) &&
!Sanitizers.has(Address) &&
!Sanitizers.has(Memory) &&
!Sanitizers.has(Thread);
@@ -131,19 +167,15 @@ bool SanitizerArgs::needsUnwindTables() const {
return Sanitizers.Mask & NeedsUnwindTables;
}
-bool SanitizerArgs::needsLTO() const {
- return Sanitizers.Mask & NeedsLTO;
-}
-
void SanitizerArgs::clear() {
Sanitizers.clear();
RecoverableSanitizers.clear();
+ TrapSanitizers.clear();
BlacklistFiles.clear();
CoverageFeatures = 0;
MsanTrackOrigins = 0;
AsanFieldPadding = 0;
AsanZeroBaseShadow = false;
- UbsanTrapOnError = false;
AsanSharedRuntime = false;
LinkCXXRuntimes = false;
}
@@ -162,10 +194,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
// Used to deduplicate diagnostics.
SanitizerMask Kinds = 0;
- SanitizerMask NotSupported = getToolchainUnsupportedKinds(TC);
+ SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
const Driver &D = TC.getDriver();
+ SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
+ SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
+
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
I != E; ++I) {
const auto *Arg = *I;
@@ -180,14 +215,20 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// sanitizers in Add are those which have been explicitly enabled.
// Diagnose them.
if (SanitizerMask KindsToDiagnose =
- Add & NotSupported & ~DiagnosedKinds) {
- // Only diagnose the new kinds.
+ Add & InvalidTrappingKinds & ~DiagnosedKinds) {
+ std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << Desc << "-fsanitize-trap=undefined";
+ DiagnosedKinds |= KindsToDiagnose;
+ }
+ Add &= ~InvalidTrappingKinds;
+ if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Desc << TC.getTriple().str();
DiagnosedKinds |= KindsToDiagnose;
}
- Add &= ~NotSupported;
+ Add &= Supported;
// Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups
// so we don't error out if -fno-rtti and -fsanitize=undefined were
@@ -216,7 +257,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Add &= ~AllRemove;
// Silently discard any unsupported sanitizers implicitly enabled through
// group expansion.
- Add &= ~NotSupported;
+ Add &= ~InvalidTrappingKinds;
+ Add &= Supported;
Kinds |= Add;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
@@ -234,22 +276,20 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Kinds &= ~Vptr;
}
- // Warn about undefined sanitizer options that require runtime support.
- UbsanTrapOnError =
- Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error, false);
- if (UbsanTrapOnError && (Kinds & NotAllowedWithTrap)) {
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForMask(D, Args, NotAllowedWithTrap)
- << "-fsanitize-undefined-trap-on-error";
- Kinds &= ~NotAllowedWithTrap;
+ // Check that LTO is enabled if we need it.
+ if ((Kinds & NeedsLTO) && !D.IsUsingLTO(Args)) {
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
}
// Warn about incompatible groups of sanitizers.
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
std::make_pair(Address, Thread), std::make_pair(Address, Memory),
std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
- std::make_pair(Leak, Memory)};
+ std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
+ std::make_pair(KernelAddress, Leak),
+ std::make_pair(KernelAddress, Thread),
+ std::make_pair(KernelAddress, Memory)};
for (auto G : IncompatibleGroups) {
SanitizerMask Group = G.first;
if (Kinds & Group) {
@@ -305,6 +345,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
RecoverableKinds &= Kinds;
RecoverableKinds &= ~Unrecoverable;
+ TrappingKinds &= Kinds;
+
// Setup blacklist files.
// Add default blacklist from resource directory.
{
@@ -460,6 +502,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Finally, initialize the set of available and recoverable sanitizers.
Sanitizers.Mask |= Kinds;
RecoverableSanitizers.Mask |= RecoverableKinds;
+ TrapSanitizers.Mask |= TrappingKinds;
}
static std::string toString(const clang::SanitizerSet &Sanitizers) {
@@ -484,8 +527,9 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
toString(RecoverableSanitizers)));
- if (UbsanTrapOnError)
- CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
+ if (!TrapSanitizers.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
for (const auto &BLPath : BlacklistFiles) {
SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
@@ -528,7 +572,9 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) &&
+ A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
+ A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
"Invalid argument in parseArgValues!");
SanitizerMask Kinds = 0;
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
OpenPOWER on IntegriCloud