aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp583
1 files changed, 400 insertions, 183 deletions
diff --git a/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp
index 8770fb1cf9fe..56d497eb4c32 100644
--- a/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp
@@ -13,11 +13,14 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SpecialCaseList.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/AArch64TargetParser.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
+#include "llvm/TargetParser/TargetParser.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
#include <memory>
@@ -33,32 +36,33 @@ static const SanitizerMask NeedsUbsanRt =
static const SanitizerMask NeedsUbsanCxxRt =
SanitizerKind::Vptr | SanitizerKind::CFI;
static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr;
-static const SanitizerMask NotAllowedWithMinimalRuntime =
- SanitizerKind::Function | SanitizerKind::Vptr;
-static const SanitizerMask RequiresPIE =
- SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo;
+static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
+static const SanitizerMask NotAllowedWithExecuteOnly =
+ SanitizerKind::Function | SanitizerKind::KCFI;
static const SanitizerMask NeedsUnwindTables =
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::DataFlow;
static const SanitizerMask SupportsCoverage =
SanitizerKind::Address | SanitizerKind::HWAddress |
SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
- SanitizerKind::MemTag | SanitizerKind::Memory |
+ SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
+ SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
SanitizerKind::KernelMemory | SanitizerKind::Leak |
SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
- SanitizerKind::Thread | SanitizerKind::ObjCCast;
+ SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
static const SanitizerMask RecoverableByDefault =
SanitizerKind::Undefined | SanitizerKind::Integer |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
static const SanitizerMask Unrecoverable =
SanitizerKind::Unreachable | SanitizerKind::Return;
-static const SanitizerMask AlwaysRecoverable =
- SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress;
+static const SanitizerMask AlwaysRecoverable = SanitizerKind::KernelAddress |
+ SanitizerKind::KernelHWAddress |
+ SanitizerKind::KCFI;
static const SanitizerMask NeedsLTO = SanitizerKind::CFI;
static const SanitizerMask TrappingSupported =
(SanitizerKind::Undefined & ~SanitizerKind::Vptr) | SanitizerKind::Integer |
@@ -72,7 +76,8 @@ static const SanitizerMask CFIClasses =
SanitizerKind::CFIUnrelatedCast;
static const SanitizerMask CompatibleWithMinimalRuntime =
TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack |
- SanitizerKind::MemTag;
+ SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
+ SanitizerKind::MemtagGlobals | SanitizerKind::KCFI;
enum CoverageFeature {
CoverageFunc = 1 << 0,
@@ -91,6 +96,15 @@ enum CoverageFeature {
CoveragePCTable = 1 << 13,
CoverageStackDepth = 1 << 14,
CoverageInlineBoolFlag = 1 << 15,
+ CoverageTraceLoads = 1 << 16,
+ CoverageTraceStores = 1 << 17,
+ CoverageControlFlow = 1 << 18,
+};
+
+enum BinaryMetadataFeature {
+ BinaryMetadataCovered = 1 << 0,
+ BinaryMetadataAtomics = 1 << 1,
+ BinaryMetadataUAR = 1 << 2,
};
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
@@ -100,7 +114,13 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
/// components. Returns OR of members of \c CoverageFeature enumeration.
-static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A);
+static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors);
+
+/// Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid
+/// components. Returns OR of members of \c BinaryMetadataFeature enumeration.
+static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors);
/// Produce an argument string from ArgList \p Args, which shows how it
/// provides some sanitizer kind from \p Mask. For example, the argument list
@@ -121,21 +141,33 @@ static std::string describeSanitizeArg(const llvm::opt::Arg *A,
/// Sanitizers set.
static std::string toString(const clang::SanitizerSet &Sanitizers);
+/// Return true if an execute-only target disallows data access to code
+/// sections.
+static bool isExecuteOnlyTarget(const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args) {
+ if (Triple.isPS5())
+ return true;
+ return Args.hasFlagNoClaim(options::OPT_mexecute_only,
+ options::OPT_mno_execute_only, false);
+}
+
static void validateSpecialCaseListFormat(const Driver &D,
std::vector<std::string> &SCLFiles,
- unsigned MalformedSCLErrorDiagID) {
+ unsigned MalformedSCLErrorDiagID,
+ bool DiagnoseErrors) {
if (SCLFiles.empty())
return;
std::string BLError;
std::unique_ptr<llvm::SpecialCaseList> SCL(
llvm::SpecialCaseList::create(SCLFiles, D.getVFS(), BLError));
- if (!SCL.get())
+ if (!SCL.get() && DiagnoseErrors)
D.Diag(MalformedSCLErrorDiagID) << BLError;
}
static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
- std::vector<std::string> &IgnorelistFiles) {
+ std::vector<std::string> &IgnorelistFiles,
+ bool DiagnoseErrors) {
struct Ignorelist {
const char *File;
SanitizerMask Mask;
@@ -158,32 +190,34 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
clang::SmallString<64> Path(D.ResourceDir);
llvm::sys::path::append(Path, "share", BL.File);
if (D.getVFS().exists(Path))
- IgnorelistFiles.push_back(std::string(Path.str()));
- else if (BL.Mask == SanitizerKind::CFI)
+ IgnorelistFiles.push_back(std::string(Path));
+ else if (BL.Mask == SanitizerKind::CFI && DiagnoseErrors)
// If cfi_ignorelist.txt cannot be found in the resource dir, driver
// should fail.
- D.Diag(clang::diag::err_drv_no_such_file) << Path;
+ D.Diag(clang::diag::err_drv_missing_sanitizer_ignorelist) << Path;
}
validateSpecialCaseListFormat(
- D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist);
+ D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist,
+ DiagnoseErrors);
}
-/// Parse -f(no-)?sanitize-(coverage-)?(white|ignore)list argument's values,
+/// Parse -f(no-)?sanitize-(coverage-)?(allow|ignore)list argument's values,
/// diagnosing any invalid file paths and validating special case list format.
static void parseSpecialCaseListArg(const Driver &D,
const llvm::opt::ArgList &Args,
std::vector<std::string> &SCLFiles,
llvm::opt::OptSpecifier SCLOptionID,
llvm::opt::OptSpecifier NoSCLOptionID,
- unsigned MalformedSCLErrorDiagID) {
+ unsigned MalformedSCLErrorDiagID,
+ bool DiagnoseErrors) {
for (const auto *Arg : Args) {
- // Match -fsanitize-(coverage-)?(white|ignore)list.
+ // Match -fsanitize-(coverage-)?(allow|ignore)list.
if (Arg->getOption().matches(SCLOptionID)) {
Arg->claim();
std::string SCLPath = Arg->getValue();
if (D.getVFS().exists(SCLPath)) {
SCLFiles.push_back(SCLPath);
- } else {
+ } else if (DiagnoseErrors) {
D.Diag(clang::diag::err_drv_no_such_file) << SCLPath;
}
// Match -fno-sanitize-ignorelist.
@@ -192,7 +226,8 @@ static void parseSpecialCaseListArg(const Driver &D,
SCLFiles.clear();
}
}
- validateSpecialCaseListFormat(D, SCLFiles, MalformedSCLErrorDiagID);
+ validateSpecialCaseListFormat(D, SCLFiles, MalformedSCLErrorDiagID,
+ DiagnoseErrors);
}
/// Sets group bits for every group that has at least one representative already
@@ -207,30 +242,31 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) {
}
static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
- const llvm::opt::ArgList &Args) {
- SanitizerMask TrapRemove; // During the loop below, the accumulated set of
- // sanitizers disabled by the current sanitizer
- // argument or any argument after it.
+ const llvm::opt::ArgList &Args,
+ bool DiagnoseErrors) {
+ SanitizerMask TrapRemove; // During the loop below, the accumulated set of
+ // sanitizers disabled by the current sanitizer
+ // argument or any argument after it.
SanitizerMask TrappingKinds;
SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported);
- for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
- I != E; ++I) {
- const auto *Arg = *I;
+ for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
Arg->claim();
SanitizerMask Add = parseArgValues(D, Arg, true);
Add &= ~TrapRemove;
- if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
+ SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups;
+ if (InvalidValues && DiagnoseErrors) {
SanitizerSet S;
S.Mask = InvalidValues;
- D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap"
- << toString(S);
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << Arg->getSpelling() << 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));
+ TrapRemove |=
+ expandSanitizerGroups(parseArgValues(D, Arg, DiagnoseErrors));
}
}
@@ -265,9 +301,7 @@ bool SanitizerArgs::needsCfiDiagRt() const {
CfiCrossDso && !ImplicitCfiRuntime;
}
-bool SanitizerArgs::requiresPIE() const {
- return NeedPIE || (Sanitizers.Mask & RequiresPIE);
-}
+bool SanitizerArgs::requiresPIE() const { return NeedPIE; }
bool SanitizerArgs::needsUnwindTables() const {
return static_cast<bool>(Sanitizers.Mask & NeedsUnwindTables);
@@ -278,17 +312,18 @@ bool SanitizerArgs::needsLTO() const {
}
SanitizerArgs::SanitizerArgs(const ToolChain &TC,
- const llvm::opt::ArgList &Args) {
+ const llvm::opt::ArgList &Args,
+ bool DiagnoseErrors) {
SanitizerMask AllRemove; // During the loop below, the accumulated set of
// sanitizers disabled by the current sanitizer
// argument or any argument after it.
- SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by
- // -fsanitize= flags (directly or via group
- // expansion), some of which may be disabled
- // later. Used to carefully prune
- // unused-argument diagnostics.
- SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
- // Used to deduplicate diagnostics.
+ SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by
+ // -fsanitize= flags (directly or via group
+ // expansion), some of which may be disabled
+ // later. Used to carefully prune
+ // unused-argument diagnostics.
+ SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
+ // Used to deduplicate diagnostics.
SanitizerMask Kinds;
const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
@@ -298,7 +333,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
const Driver &D = TC.getDriver();
- SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
+ SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args, DiagnoseErrors);
SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
MinimalRuntime =
@@ -310,19 +345,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
bool RemoveObjectSizeAtO0 =
!OptLevel || OptLevel->getOption().matches(options::OPT_O0);
- for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
- I != E; ++I) {
- const auto *Arg = *I;
+ for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
Arg->claim();
- SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true);
+ SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
if (RemoveObjectSizeAtO0) {
AllRemove |= SanitizerKind::ObjectSize;
// The user explicitly enabled the object size sanitizer. Warn
// that this does nothing at -O0.
- if (Add & SanitizerKind::ObjectSize)
+ if ((Add & SanitizerKind::ObjectSize) && DiagnoseErrors)
D.Diag(diag::warn_drv_object_size_disabled_O0)
<< Arg->getAsString(Args);
}
@@ -336,9 +369,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Diagnose them.
if (SanitizerMask KindsToDiagnose =
Add & InvalidTrappingKinds & ~DiagnosedKinds) {
- std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << Desc << "-fsanitize-trap=undefined";
+ if (DiagnoseErrors) {
+ std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << Desc << "-fsanitize-trap=undefined";
+ }
DiagnosedKinds |= KindsToDiagnose;
}
Add &= ~InvalidTrappingKinds;
@@ -346,14 +381,45 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (MinimalRuntime) {
if (SanitizerMask KindsToDiagnose =
Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) {
- std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << Desc << "-fsanitize-minimal-runtime";
+ if (DiagnoseErrors) {
+ std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << Desc << "-fsanitize-minimal-runtime";
+ }
DiagnosedKinds |= KindsToDiagnose;
}
Add &= ~NotAllowedWithMinimalRuntime;
}
+ if (llvm::opt::Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
+ StringRef CM = A->getValue();
+ if (CM != "small" &&
+ (Add & SanitizerKind::Function & ~DiagnosedKinds)) {
+ if (DiagnoseErrors)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-fsanitize=function"
+ << "-mcmodel=small";
+ Add &= ~SanitizerKind::Function;
+ DiagnosedKinds |= SanitizerKind::Function;
+ }
+ }
+ // -fsanitize=function and -fsanitize=kcfi instrument indirect function
+ // calls to load a type hash before the function label. Therefore, an
+ // execute-only target doesn't support the function and kcfi sanitizers.
+ const llvm::Triple &Triple = TC.getTriple();
+ if (isExecuteOnlyTarget(Triple, Args)) {
+ if (SanitizerMask KindsToDiagnose =
+ Add & NotAllowedWithExecuteOnly & ~DiagnosedKinds) {
+ if (DiagnoseErrors) {
+ std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << Desc << Triple.str();
+ }
+ DiagnosedKinds |= KindsToDiagnose;
+ }
+ Add &= ~NotAllowedWithExecuteOnly;
+ }
+
// FIXME: Make CFI on member function calls compatible with cross-DSO CFI.
// There are currently two problems:
// - Virtual function call checks need to pass a pointer to the function
@@ -365,17 +431,20 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Fixing both of those may require changes to the cross-DSO CFI
// interface.
if (CfiCrossDso && (Add & SanitizerKind::CFIMFCall & ~DiagnosedKinds)) {
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fsanitize=cfi-mfcall"
- << "-fsanitize-cfi-cross-dso";
+ if (DiagnoseErrors)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize=cfi-mfcall"
+ << "-fsanitize-cfi-cross-dso";
Add &= ~SanitizerKind::CFIMFCall;
DiagnosedKinds |= SanitizerKind::CFIMFCall;
}
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();
+ if (DiagnoseErrors) {
+ std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Desc << TC.getTriple().str();
+ }
DiagnosedKinds |= KindsToDiagnose;
}
Add &= Supported;
@@ -386,15 +455,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if ((Add & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) {
if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) {
assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) &&
- "RTTI disabled without -fno-rtti option?");
+ "RTTI disabled without -fno-rtti option?");
// The user explicitly passed -fno-rtti with -fsanitize=vptr, but
// the vptr sanitizer requires RTTI, so this is a user error.
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
+ if (DiagnoseErrors)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
} else {
// The vptr sanitizer requires RTTI, but RTTI is disabled (by
// default). Warn that the vptr sanitizer is being disabled.
- D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
+ if (DiagnoseErrors)
+ D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
}
// Take out the Vptr sanitizer from the enabled sanitizers
@@ -410,6 +481,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (MinimalRuntime) {
Add &= ~NotAllowedWithMinimalRuntime;
}
+ // NotAllowedWithExecuteOnly is silently discarded on an execute-only
+ // target if implicitly enabled through group expansion.
+ if (isExecuteOnlyTarget(Triple, Args))
+ Add &= ~NotAllowedWithExecuteOnly;
if (CfiCrossDso)
Add &= ~SanitizerKind::CFIMFCall;
Add &= Supported;
@@ -429,7 +504,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Kinds |= Add;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
Arg->claim();
- SanitizerMask Remove = parseArgValues(D, Arg, true);
+ SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
AllRemove |= expandSanitizerGroups(Remove);
}
}
@@ -469,7 +544,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
std::make_pair(SanitizerKind::MemTag,
SanitizerKind::Address | SanitizerKind::KernelAddress |
SanitizerKind::HWAddress |
- SanitizerKind::KernelHWAddress)};
+ SanitizerKind::KernelHWAddress),
+ std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function)};
// Enable toolchain specific default sanitizers if not explicitly disabled.
SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
@@ -490,16 +566,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
// Check that LTO is enabled if we need it.
- if ((Kinds & NeedsLTO) && !D.isUsingLTO()) {
+ if ((Kinds & NeedsLTO) && !D.isUsingLTO() && DiagnoseErrors) {
D.Diag(diag::err_drv_argument_only_allowed_with)
<< lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
}
- if ((Kinds & SanitizerKind::ShadowCallStack) &&
- ((TC.getTriple().isAArch64() &&
- !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) ||
- TC.getTriple().isRISCV()) &&
- !Args.hasArg(options::OPT_ffixed_x18)) {
+ if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().isAArch64() &&
+ !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) &&
+ !Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) {
D.Diag(diag::err_drv_argument_only_allowed_with)
<< lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack)
<< "-ffixed-x18";
@@ -518,8 +592,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (KindsToDiagnose) {
SanitizerSet S;
S.Mask = KindsToDiagnose;
- D.Diag(diag::err_drv_unsupported_opt_for_target)
- << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str();
+ if (DiagnoseErrors)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str();
Kinds &= ~KindsToDiagnose;
}
}
@@ -529,9 +604,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask Group = G.first;
if (Kinds & Group) {
if (SanitizerMask Incompatible = Kinds & G.second) {
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForMask(D, Args, Group)
- << lastArgumentForMask(D, Args, Incompatible);
+ if (DiagnoseErrors)
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForMask(D, Args, Group)
+ << lastArgumentForMask(D, Args, Incompatible);
Kinds &= ~Incompatible;
}
}
@@ -547,29 +623,31 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask DiagnosedAlwaysRecoverableKinds;
for (const auto *Arg : Args) {
if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
- SanitizerMask Add = parseArgValues(D, Arg, true);
+ SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
// Report error if user explicitly tries to recover from unrecoverable
// sanitizer.
if (SanitizerMask KindsToDiagnose =
Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
SanitizerSet SetToDiagnose;
SetToDiagnose.Mask |= KindsToDiagnose;
- D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << toString(SetToDiagnose);
+ if (DiagnoseErrors)
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedUnrecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds |= expandSanitizerGroups(Add);
Arg->claim();
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
- SanitizerMask Remove = parseArgValues(D, Arg, true);
+ SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
// Report error if user explicitly tries to disable recovery from
// always recoverable sanitizer.
if (SanitizerMask KindsToDiagnose =
Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) {
SanitizerSet SetToDiagnose;
SetToDiagnose.Mask |= KindsToDiagnose;
- D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << toString(SetToDiagnose);
+ if (DiagnoseErrors)
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds &= ~expandSanitizerGroups(Remove);
@@ -586,42 +664,57 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Add default ignorelist from resource directory for activated sanitizers,
// and validate special case lists format.
if (!Args.hasArgNoClaim(options::OPT_fno_sanitize_ignorelist))
- addDefaultIgnorelists(D, Kinds, SystemIgnorelistFiles);
+ addDefaultIgnorelists(D, Kinds, SystemIgnorelistFiles, DiagnoseErrors);
// Parse -f(no-)?sanitize-ignorelist options.
// This also validates special case lists format.
- parseSpecialCaseListArg(D, Args, UserIgnorelistFiles,
- options::OPT_fsanitize_ignorelist_EQ,
- options::OPT_fno_sanitize_ignorelist,
- clang::diag::err_drv_malformed_sanitizer_ignorelist);
+ parseSpecialCaseListArg(
+ D, Args, UserIgnorelistFiles, options::OPT_fsanitize_ignorelist_EQ,
+ options::OPT_fno_sanitize_ignorelist,
+ clang::diag::err_drv_malformed_sanitizer_ignorelist, DiagnoseErrors);
// Parse -f[no-]sanitize-memory-track-origins[=level] options.
if (AllAddedKinds & SanitizerKind::Memory) {
if (Arg *A =
Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
- options::OPT_fsanitize_memory_track_origins,
options::OPT_fno_sanitize_memory_track_origins)) {
- if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
- MsanTrackOrigins = 2;
- } else if (A->getOption().matches(
- options::OPT_fno_sanitize_memory_track_origins)) {
- MsanTrackOrigins = 0;
- } else {
+ if (!A->getOption().matches(
+ options::OPT_fno_sanitize_memory_track_origins)) {
StringRef S = A->getValue();
if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
MsanTrackOrigins > 2) {
- D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ if (DiagnoseErrors)
+ D.Diag(clang::diag::err_drv_invalid_value)
+ << A->getAsString(Args) << S;
}
}
}
- MsanUseAfterDtor =
- Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor,
- options::OPT_fno_sanitize_memory_use_after_dtor,
- MsanUseAfterDtor);
- NeedPIE |= !(TC.getTriple().isOSLinux() &&
- TC.getTriple().getArch() == llvm::Triple::x86_64);
+ MsanUseAfterDtor = Args.hasFlag(
+ options::OPT_fsanitize_memory_use_after_dtor,
+ options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor);
+ MsanParamRetval = Args.hasFlag(
+ options::OPT_fsanitize_memory_param_retval,
+ options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
+ } else if (AllAddedKinds & SanitizerKind::KernelMemory) {
+ MsanUseAfterDtor = false;
+ MsanParamRetval = Args.hasFlag(
+ options::OPT_fsanitize_memory_param_retval,
+ options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
} else {
MsanUseAfterDtor = false;
+ MsanParamRetval = false;
+ }
+
+ if (AllAddedKinds & SanitizerKind::MemTag) {
+ StringRef S =
+ Args.getLastArgValue(options::OPT_fsanitize_memtag_mode_EQ, "sync");
+ if (S == "async" || S == "sync") {
+ MemtagMode = S.str();
+ } else {
+ D.Diag(clang::diag::err_drv_invalid_value_with_suggestion)
+ << "-fsanitize-memtag-mode=" << S << "{async, sync}";
+ MemtagMode = "sync";
+ }
}
if (AllAddedKinds & SanitizerKind::Thread) {
@@ -643,7 +736,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
CfiICallGeneralizePointers =
Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
- if (CfiCrossDso && CfiICallGeneralizePointers)
+ CfiICallNormalizeIntegers =
+ Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
+
+ if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fsanitize-cfi-cross-dso"
<< "-fsanitize-cfi-icall-generalize-pointers";
@@ -653,19 +749,29 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
options::OPT_fno_sanitize_cfi_canonical_jump_tables, true);
}
+ if (AllAddedKinds & SanitizerKind::KCFI) {
+ CfiICallNormalizeIntegers =
+ Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
+
+ if (AllAddedKinds & SanitizerKind::CFI && DiagnoseErrors)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize=kcfi"
+ << lastArgumentForMask(D, Args, SanitizerKind::CFI);
+ }
+
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
options::OPT_fno_sanitize_stats, false);
if (MinimalRuntime) {
SanitizerMask IncompatibleMask =
Kinds & ~setGroupBits(CompatibleWithMinimalRuntime);
- if (IncompatibleMask)
+ if (IncompatibleMask && DiagnoseErrors)
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
<< "-fsanitize-minimal-runtime"
<< lastArgumentForMask(D, Args, IncompatibleMask);
SanitizerMask NonTrappingCfi = Kinds & SanitizerKind::CFI & ~TrappingKinds;
- if (NonTrappingCfi)
+ if (NonTrappingCfi && DiagnoseErrors)
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< "fsanitize-minimal-runtime"
<< "fsanitize-trap=cfi";
@@ -681,13 +787,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
.getAsInteger(0, LegacySanitizeCoverage)) {
CoverageFeatures = 0;
Arg->claim();
- if (LegacySanitizeCoverage != 0) {
+ if (LegacySanitizeCoverage != 0 && DiagnoseErrors) {
D.Diag(diag::warn_drv_deprecated_arg)
<< Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard";
}
continue;
}
- CoverageFeatures |= parseCoverageFeatures(D, Arg);
+ CoverageFeatures |= parseCoverageFeatures(D, Arg, DiagnoseErrors);
// Disable coverage and not claim the flags if there is at least one
// non-supporting sanitizer.
@@ -698,56 +804,60 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
Arg->claim();
- CoverageFeatures &= ~parseCoverageFeatures(D, Arg);
+ CoverageFeatures &= ~parseCoverageFeatures(D, Arg, DiagnoseErrors);
}
}
// Choose at most one coverage type: function, bb, or edge.
- if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB))
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << "-fsanitize-coverage=func"
- << "-fsanitize-coverage=bb";
- if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge))
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << "-fsanitize-coverage=func"
- << "-fsanitize-coverage=edge";
- if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << "-fsanitize-coverage=bb"
- << "-fsanitize-coverage=edge";
- // Basic block tracing and 8-bit counters require some type of coverage
- // enabled.
- if (CoverageFeatures & CoverageTraceBB)
- D.Diag(clang::diag::warn_drv_deprecated_arg)
- << "-fsanitize-coverage=trace-bb"
- << "-fsanitize-coverage=trace-pc-guard";
- if (CoverageFeatures & Coverage8bitCounters)
- D.Diag(clang::diag::warn_drv_deprecated_arg)
- << "-fsanitize-coverage=8bit-counters"
- << "-fsanitize-coverage=trace-pc-guard";
+ if (DiagnoseErrors) {
+ if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB))
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize-coverage=func"
+ << "-fsanitize-coverage=bb";
+ if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge))
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize-coverage=func"
+ << "-fsanitize-coverage=edge";
+ if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize-coverage=bb"
+ << "-fsanitize-coverage=edge";
+ // Basic block tracing and 8-bit counters require some type of coverage
+ // enabled.
+ if (CoverageFeatures & CoverageTraceBB)
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
+ << "-fsanitize-coverage=trace-bb"
+ << "-fsanitize-coverage=trace-pc-guard";
+ if (CoverageFeatures & Coverage8bitCounters)
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
+ << "-fsanitize-coverage=8bit-counters"
+ << "-fsanitize-coverage=trace-pc-guard";
+ }
int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard |
- CoverageInline8bitCounters |
- CoverageInlineBoolFlag;
+ CoverageInline8bitCounters | CoverageTraceLoads |
+ CoverageTraceStores | CoverageInlineBoolFlag |
+ CoverageControlFlow;
if ((CoverageFeatures & InsertionPointTypes) &&
- !(CoverageFeatures & InstrumentationTypes)) {
+ !(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) {
D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=[func|bb|edge]"
- << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
+ << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],["
+ "control-flow]";
}
// trace-pc w/o func/bb/edge implies edge.
if (!(CoverageFeatures & InsertionPointTypes)) {
if (CoverageFeatures &
(CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters |
- CoverageInlineBoolFlag))
+ CoverageInlineBoolFlag | CoverageControlFlow))
CoverageFeatures |= CoverageEdge;
if (CoverageFeatures & CoverageStackDepth)
CoverageFeatures |= CoverageFunc;
}
- // Parse -fsanitize-coverage-(ignore|white)list options if coverage enabled.
+ // Parse -fsanitize-coverage-(allow|ignore)list options if coverage enabled.
// This also validates special case lists format.
// Here, OptSpecifier() acts as a never-matching command-line argument.
// So, there is no way to clear coverage lists but you can append to them.
@@ -755,11 +865,39 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
parseSpecialCaseListArg(
D, Args, CoverageAllowlistFiles,
options::OPT_fsanitize_coverage_allowlist, OptSpecifier(),
- clang::diag::err_drv_malformed_sanitizer_coverage_whitelist);
+ clang::diag::err_drv_malformed_sanitizer_coverage_allowlist,
+ DiagnoseErrors);
parseSpecialCaseListArg(
D, Args, CoverageIgnorelistFiles,
options::OPT_fsanitize_coverage_ignorelist, OptSpecifier(),
- clang::diag::err_drv_malformed_sanitizer_coverage_ignorelist);
+ clang::diag::err_drv_malformed_sanitizer_coverage_ignorelist,
+ DiagnoseErrors);
+ }
+
+ // Parse -f(no-)?sanitize-metadata.
+ for (const auto *Arg :
+ Args.filtered(options::OPT_fexperimental_sanitize_metadata_EQ,
+ options::OPT_fno_experimental_sanitize_metadata_EQ)) {
+ if (Arg->getOption().matches(
+ options::OPT_fexperimental_sanitize_metadata_EQ)) {
+ Arg->claim();
+ BinaryMetadataFeatures |=
+ parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+ } else {
+ Arg->claim();
+ BinaryMetadataFeatures &=
+ ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+ }
+ }
+
+ // Parse -fsanitize-metadata-ignorelist option if enabled.
+ if (BinaryMetadataFeatures) {
+ parseSpecialCaseListArg(
+ D, Args, BinaryMetadataIgnorelistFiles,
+ options::OPT_fexperimental_sanitize_metadata_ignorelist_EQ,
+ OptSpecifier(), // Cannot clear ignore list, only append.
+ clang::diag::err_drv_malformed_sanitizer_metadata_ignorelist,
+ DiagnoseErrors);
}
SharedRuntime =
@@ -773,12 +911,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
NeedPIE |= TC.getTriple().isOSFuchsia();
if (Arg *A =
Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
- StringRef S = A->getValue();
- // Legal values are 0 and 1, 2, but in future we may add more levels.
- if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
- AsanFieldPadding > 2) {
- D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
- }
+ StringRef S = A->getValue();
+ // Legal values are 0 and 1, 2, but in future we may add more levels.
+ if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
+ AsanFieldPadding > 2) &&
+ DiagnoseErrors) {
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
}
if (Arg *WindowsDebugRTArg =
@@ -789,13 +928,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
case options::OPT__SLASH_MTd:
case options::OPT__SLASH_MDd:
case options::OPT__SLASH_LDd:
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << WindowsDebugRTArg->getAsString(Args)
- << lastArgumentForMask(D, Args, SanitizerKind::Address);
- D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
+ if (DiagnoseErrors) {
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << WindowsDebugRTArg->getAsString(Args)
+ << lastArgumentForMask(D, Args, SanitizerKind::Address);
+ D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
+ }
}
}
+ StableABI = Args.hasFlag(options::OPT_fsanitize_stable_abi,
+ options::OPT_fno_sanitize_stable_abi, false);
+
AsanUseAfterScope = Args.hasFlag(
options::OPT_fsanitize_address_use_after_scope,
options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
@@ -810,18 +954,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
options::OPT_fno_sanitize_address_outline_instrumentation,
AsanOutlineInstrumentation);
- // As a workaround for a bug in gold 2.26 and earlier, dead stripping of
- // globals in ASan is disabled by default on ELF targets.
- // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002
- AsanGlobalsDeadStripping =
- !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() ||
- TC.getTriple().isPS4() ||
- Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping);
+ AsanGlobalsDeadStripping = Args.hasFlag(
+ options::OPT_fsanitize_address_globals_dead_stripping,
+ options::OPT_fno_sanitize_address_globals_dead_stripping, true);
+ // Enable ODR indicators which allow better handling of mixed instrumented
+ // and uninstrumented globals. Disable them for Windows where weak odr
+ // indicators (.weak.__odr_asan_gen*) may cause multiple definition linker
+ // errors in the absence of -lldmingw.
AsanUseOdrIndicator =
Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator,
options::OPT_fno_sanitize_address_use_odr_indicator,
- AsanUseOdrIndicator);
+ !TC.getTriple().isOSWindows());
if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) {
AsanInvalidPointerCmp = true;
@@ -840,9 +984,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (const auto *Arg =
Args.getLastArg(options::OPT_sanitize_address_destructor_EQ)) {
auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue());
- if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid) {
+ if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) {
TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
}
AsanDtorKind = parsedAsanDtorKind;
}
@@ -852,9 +996,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
auto parsedAsanUseAfterReturn =
AsanDetectStackUseAfterReturnModeFromString(Arg->getValue());
if (parsedAsanUseAfterReturn ==
- llvm::AsanDetectStackUseAfterReturnMode::Invalid) {
+ llvm::AsanDetectStackUseAfterReturnMode::Invalid &&
+ DiagnoseErrors) {
TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
}
AsanUseAfterReturn = parsedAsanUseAfterReturn;
}
@@ -864,7 +1009,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address.
SanitizerMask DetectInvalidPointerPairs =
SanitizerKind::PointerCompare | SanitizerKind::PointerSubtract;
- if (AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) {
+ if ((AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) &&
+ DiagnoseErrors) {
TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with)
<< lastArgumentForMask(D, Args,
SanitizerKind::PointerCompare |
@@ -877,7 +1023,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (Arg *HwasanAbiArg =
Args.getLastArg(options::OPT_fsanitize_hwaddress_abi_EQ)) {
HwasanAbi = HwasanAbiArg->getValue();
- if (HwasanAbi != "platform" && HwasanAbi != "interceptor")
+ if (HwasanAbi != "platform" && HwasanAbi != "interceptor" &&
+ DiagnoseErrors)
D.Diag(clang::diag::err_drv_invalid_value)
<< HwasanAbiArg->getAsString(Args) << HwasanAbi;
} else {
@@ -956,7 +1103,8 @@ static void addIncludeLinkerOption(const ToolChain &TC,
}
static bool hasTargetFeatureMTE(const llvm::opt::ArgStringList &CmdArgs) {
- for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End; ++Start) {
+ for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End;
+ ++Start) {
auto It = std::find(Start, End, StringRef("+mte"));
if (It == End)
break;
@@ -973,13 +1121,16 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
// NVPTX doesn't currently support sanitizers. Bailing out here means
// that e.g. -fsanitize=address applies only to host code, which is what we
// want for now.
- //
- // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize.
- if (TC.getTriple().isNVPTX() ||
- (TC.getTriple().isAMDGPU() &&
- !Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
- false)))
+ if (TC.getTriple().isNVPTX())
return;
+ // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize.
+ bool GPUSanitize = false;
+ if (TC.getTriple().isAMDGPU()) {
+ if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
+ true))
+ return;
+ GPUSanitize = true;
+ }
// Translate available CoverageFeatures to corresponding clang-cc1 flags.
// Do it even if Sanitizers.empty() since some forms of coverage don't require
@@ -1003,7 +1154,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
"-fsanitize-coverage-inline-bool-flag"),
std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"),
std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
- std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")};
+ std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"),
+ std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"),
+ std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores"),
+ std::make_pair(CoverageControlFlow, "-fsanitize-coverage-control-flow")};
for (auto F : CoverageFlags) {
if (CoverageFeatures & F.first)
CmdArgs.push_back(F.second);
@@ -1013,6 +1167,23 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-ignorelist=",
CoverageIgnorelistFiles);
+ if (!GPUSanitize) {
+ // Translate available BinaryMetadataFeatures to corresponding clang-cc1
+ // flags. Does not depend on any other sanitizers. Unsupported on GPUs.
+ const std::pair<int, std::string> BinaryMetadataFlags[] = {
+ std::make_pair(BinaryMetadataCovered, "covered"),
+ std::make_pair(BinaryMetadataAtomics, "atomics"),
+ std::make_pair(BinaryMetadataUAR, "uar")};
+ for (const auto &F : BinaryMetadataFlags) {
+ if (BinaryMetadataFeatures & F.first)
+ CmdArgs.push_back(
+ Args.MakeArgString("-fexperimental-sanitize-metadata=" + F.second));
+ }
+ addSpecialCaseListOpt(Args, CmdArgs,
+ "-fexperimental-sanitize-metadata-ignorelist=",
+ BinaryMetadataIgnorelistFiles);
+ }
+
if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
// Instruct the code generator to embed linker directives in the object file
// that cause the required runtime libraries to be linked.
@@ -1061,6 +1232,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (MsanUseAfterDtor)
CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
+ if (!MsanParamRetval)
+ CmdArgs.push_back("-fno-sanitize-memory-param-retval");
+
// FIXME: Pass these parameters as function attributes, not as -llvm flags.
if (!TsanMemoryAccess) {
CmdArgs.push_back("-mllvm");
@@ -1088,6 +1262,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (CfiICallGeneralizePointers)
CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
+ if (CfiICallNormalizeIntegers)
+ CmdArgs.push_back("-fsanitize-cfi-icall-experimental-normalize-integers");
+
if (CfiCanonicalJumpTables)
CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
@@ -1110,8 +1287,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (AsanGlobalsDeadStripping)
CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
- if (AsanUseOdrIndicator)
- CmdArgs.push_back("-fsanitize-address-use-odr-indicator");
+ if (!AsanUseOdrIndicator)
+ CmdArgs.push_back("-fno-sanitize-address-use-odr-indicator");
if (AsanInvalidPointerCmp) {
CmdArgs.push_back("-mllvm");
@@ -1128,6 +1305,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back("-asan-instrumentation-with-call-threshold=0");
}
+ // When emitting Stable ABI instrumentation, force outlining calls and avoid
+ // inlining shadow memory poisoning. While this is a big performance burden
+ // for now it allows full abstraction from implementation details.
+ if (StableABI) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-asan-instrumentation-with-call-threshold=0");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-asan-max-inline-poisoning-size=0");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-asan-guard-against-version-mismatch=0");
+ }
+
// Only pass the option to the frontend if the user requested,
// otherwise the frontend will just use the codegen default.
if (AsanDtorKind != llvm::AsanDtorKind::Invalid) {
@@ -1146,7 +1335,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("hwasan-abi=" + HwasanAbi));
}
- if (Sanitizers.has(SanitizerKind::HWAddress) && TC.getTriple().isAArch64()) {
+ if (Sanitizers.has(SanitizerKind::HWAddress) && !HwasanUseAliases) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+tagged-globals");
}
@@ -1187,7 +1376,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
<< "-fvisibility=";
}
- if (Sanitizers.has(SanitizerKind::MemTag) && !hasTargetFeatureMTE(CmdArgs))
+ if (Sanitizers.has(SanitizerKind::MemtagStack) &&
+ !hasTargetFeatureMTE(CmdArgs))
TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature);
}
@@ -1215,12 +1405,13 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
Kinds |= Kind;
else if (DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
return Kinds;
}
-int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
+int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors) {
assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
A->getOption().matches(options::OPT_fno_sanitize_coverage));
int Features = 0;
@@ -1243,10 +1434,36 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
.Case("inline-bool-flag", CoverageInlineBoolFlag)
.Case("pc-table", CoveragePCTable)
.Case("stack-depth", CoverageStackDepth)
+ .Case("trace-loads", CoverageTraceLoads)
+ .Case("trace-stores", CoverageTraceStores)
+ .Case("control-flow", CoverageControlFlow)
+ .Default(0);
+ if (F == 0 && DiagnoseErrors)
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Value;
+ Features |= F;
+ }
+ return Features;
+}
+
+int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors) {
+ assert(
+ A->getOption().matches(options::OPT_fexperimental_sanitize_metadata_EQ) ||
+ A->getOption().matches(
+ options::OPT_fno_experimental_sanitize_metadata_EQ));
+ int Features = 0;
+ for (int i = 0, n = A->getNumValues(); i != n; ++i) {
+ const char *Value = A->getValue(i);
+ int F = llvm::StringSwitch<int>(Value)
+ .Case("covered", BinaryMetadataCovered)
+ .Case("atomics", BinaryMetadataAtomics)
+ .Case("uar", BinaryMetadataUAR)
+ .Case("all", ~0)
.Default(0);
- if (F == 0)
+ if (F == 0 && DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
Features |= F;
}
return Features;
@@ -1273,8 +1490,8 @@ std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
}
std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) {
- assert(A->getOption().matches(options::OPT_fsanitize_EQ)
- && "Invalid argument in describeSanitizerArg!");
+ assert(A->getOption().matches(options::OPT_fsanitize_EQ) &&
+ "Invalid argument in describeSanitizerArg!");
std::string Sanitizers;
for (int i = 0, n = A->getNumValues(); i != n; ++i) {