[Driver] Fix ToolChain::getSanitizerArgs

The driver uses class SanitizerArgs to store parsed sanitizer arguments. It keeps a cached
SanitizerArgs object in ToolChain and uses it for different jobs. This does not work if
the sanitizer options are different for different jobs, which could happen when an
offloading toolchain translates the options for different jobs.

To fix this, SanitizerArgs should be created by using the actual arguments passed
to jobs instead of the original arguments passed to the driver, since the toolchain
may change the original arguments. And the sanitizer arguments should be diagnose
once.

This patch also fixes HIP toolchain for handling -fgpu-sanitize: a warning is emitted
for GPU's not supporting sanitizer and skipped. This is for backward compatibility
with existing -fsanitize options. -fgpu-sanitize is also turned on by default.

Reviewed by: Artem Belevich, Evgenii Stepanov

Differential Revision: https://reviews.llvm.org/D111443
This commit is contained in:
Yaxun (Sam) Liu 2021-10-06 23:55:26 -04:00
parent 92fc60bc62
commit 0309e50f33
47 changed files with 338 additions and 218 deletions

View File

@ -100,6 +100,14 @@ def err_drv_bad_offload_arch_combo : Error<
"invalid offload arch combinations: '%0' and '%1' (for a specific processor, "
"a feature should either exist in all offload archs, or not exist in any "
"offload archs)">;
def warn_drv_unsupported_option_for_offload_arch_req_feature : Warning<
"ignoring '%0' option as it is not currently supported for "
"offload arch '%1'. Use it with an offload arch containing '%2' instead">,
InGroup<OptionIgnored>;
def warn_drv_unsupported_option_for_target : Warning<
"ignoring '%0' option as it is not currently supported for target '%1'">,
InGroup<OptionIgnored>;
def err_drv_invalid_thread_model_for_target : Error<
"invalid thread model '%0' in '%1' for this target">;
def err_drv_invalid_linker_name : Error<

View File

@ -65,7 +65,8 @@ class SanitizerArgs {
public:
/// Parses the sanitizer arguments from an argument list.
SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
bool DiagnoseErrors = true);
bool needsSharedRt() const { return SharedRuntime; }

View File

@ -162,7 +162,7 @@ private:
Tool *getOffloadBundler() const;
Tool *getOffloadWrapper() const;
mutable std::unique_ptr<SanitizerArgs> SanitizerArguments;
mutable bool SanitizerArgsChecked = false;
mutable std::unique_ptr<XRayArgs> XRayArguments;
/// The effective clang triple for the current Job.
@ -266,7 +266,7 @@ public:
const Multilib &getMultilib() const { return SelectedMultilib; }
const SanitizerArgs& getSanitizerArgs() const;
SanitizerArgs getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const;
const XRayArgs& getXRayArgs() const;
@ -485,15 +485,15 @@ public:
virtual bool isPICDefault() const = 0;
/// Test whether this toolchain defaults to PIE.
virtual bool isPIEDefault() const = 0;
virtual bool isPIEDefault(const llvm::opt::ArgList &Args) const = 0;
/// Test whether this toolchaind defaults to non-executable stacks.
virtual bool isNoExecStackDefault() const;
/// Tests whether this toolchain forces its default for PIC, PIE or
/// non-PIC. If this returns true, any PIC related flags should be ignored
/// and instead the results of \c isPICDefault() and \c isPIEDefault() are
/// used exclusively.
/// and instead the results of \c isPICDefault() and \c isPIEDefault(const
/// llvm::opt::ArgList &Args) are used exclusively.
virtual bool isPICDefaultForced() const = 0;
/// SupportsProfiling - Does this tool chain support -pg.

View File

@ -2914,7 +2914,6 @@ class OffloadingActionBuilder final {
class HIPActionBuilder final : public CudaActionBuilderBase {
/// The linker inputs obtained for each device arch.
SmallVector<ActionList, 8> DeviceLinkerInputs;
bool GPUSanitize;
// The default bundling behavior depends on the type of output, therefore
// BundleOutput needs to be tri-value: None, true, or false.
// Bundle code objects except --no-gpu-output is specified for device
@ -2927,8 +2926,6 @@ class OffloadingActionBuilder final {
const Driver::InputList &Inputs)
: CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {
DefaultCudaArch = CudaArch::GFX803;
GPUSanitize = Args.hasFlag(options::OPT_fgpu_sanitize,
options::OPT_fno_gpu_sanitize, false);
if (Args.hasArg(options::OPT_gpu_bundle_output,
options::OPT_no_gpu_bundle_output))
BundleOutput = Args.hasFlag(options::OPT_gpu_bundle_output,

View File

@ -102,7 +102,8 @@ 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);
/// Produce an argument string from ArgList \p Args, which shows how it
/// provides some sanitizer kind from \p Mask. For example, the argument list
@ -125,19 +126,21 @@ static std::string toString(const clang::SanitizerSet &Sanitizers);
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;
@ -161,13 +164,14 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
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)
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;
}
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,
@ -177,7 +181,8 @@ static void parseSpecialCaseListArg(const Driver &D,
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.
if (Arg->getOption().matches(SCLOptionID)) {
@ -185,7 +190,7 @@ static void parseSpecialCaseListArg(const Driver &D,
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.
@ -194,7 +199,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
@ -209,7 +215,8 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) {
}
static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
const llvm::opt::ArgList &Args) {
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.
@ -223,7 +230,8 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
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"
@ -232,7 +240,8 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
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));
}
}
@ -280,7 +289,8 @@ 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.
@ -300,7 +310,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 =
@ -317,14 +327,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
const auto *Arg = *I;
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);
}
@ -338,9 +348,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(*I, KindsToDiagnose);
D.Diag(diag::err_drv_argument_not_allowed_with)
<< Desc << "-fsanitize-trap=undefined";
}
DiagnosedKinds |= KindsToDiagnose;
}
Add &= ~InvalidTrappingKinds;
@ -348,9 +360,11 @@ 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(*I, KindsToDiagnose);
D.Diag(diag::err_drv_argument_not_allowed_with)
<< Desc << "-fsanitize-minimal-runtime";
}
DiagnosedKinds |= KindsToDiagnose;
}
Add &= ~NotAllowedWithMinimalRuntime;
@ -367,17 +381,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(*I, KindsToDiagnose);
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Desc << TC.getTriple().str();
}
DiagnosedKinds |= KindsToDiagnose;
}
Add &= Supported;
@ -391,12 +408,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
"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
@ -431,7 +450,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);
}
}
@ -492,7 +511,7 @@ 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";
}
@ -501,7 +520,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
((TC.getTriple().isAArch64() &&
!llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) ||
TC.getTriple().isRISCV()) &&
!Args.hasArg(options::OPT_ffixed_x18)) {
!Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) {
D.Diag(diag::err_drv_argument_only_allowed_with)
<< lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack)
<< "-ffixed-x18";
@ -520,8 +539,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;
}
}
@ -531,9 +551,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;
}
}
@ -549,29 +570,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->getOption().getName() << 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->getOption().getName() << toString(SetToDiagnose);
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds &= ~expandSanitizerGroups(Remove);
@ -588,14 +611,14 @@ 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) {
@ -612,7 +635,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
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;
}
}
}
@ -645,7 +670,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
CfiICallGeneralizePointers =
Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
if (CfiCrossDso && CfiICallGeneralizePointers)
if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fsanitize-cfi-cross-dso"
<< "-fsanitize-cfi-icall-generalize-pointers";
@ -661,13 +686,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
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";
@ -683,13 +708,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.
@ -700,39 +725,41 @@ 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 | CoverageTraceLoads |
CoverageTraceStores | CoverageInlineBoolFlag;
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]";
@ -757,11 +784,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
parseSpecialCaseListArg(
D, Args, CoverageAllowlistFiles,
options::OPT_fsanitize_coverage_allowlist, OptSpecifier(),
clang::diag::err_drv_malformed_sanitizer_coverage_allowlist);
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);
}
SharedRuntime =
@ -777,8 +806,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
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) {
if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
AsanFieldPadding > 2) &&
DiagnoseErrors) {
D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
}
}
@ -791,10 +821,12 @@ 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);
}
}
}
@ -842,7 +874,7 @@ 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();
}
@ -854,7 +886,8 @@ 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();
}
@ -866,7 +899,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 |
@ -879,7 +913,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 {
@ -979,8 +1014,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
// 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)))
!Args.hasFlag(options::OPT_fgpu_sanitize,
options::OPT_fno_gpu_sanitize)))
return;
// Translate available CoverageFeatures to corresponding clang-cc1 flags.
@ -1224,7 +1259,8 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
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;
@ -1250,7 +1286,7 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
.Case("trace-loads", CoverageTraceLoads)
.Case("trace-stores", CoverageTraceStores)
.Default(0);
if (F == 0)
if (F == 0 && DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
Features |= F;

View File

@ -114,10 +114,11 @@ bool ToolChain::isNoExecStackDefault() const {
return false;
}
const SanitizerArgs& ToolChain::getSanitizerArgs() const {
if (!SanitizerArguments.get())
SanitizerArguments.reset(new SanitizerArgs(*this, Args));
return *SanitizerArguments.get();
SanitizerArgs
ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const {
SanitizerArgs SanArgs(*this, JobArgs, !SanitizerArgsChecked);
SanitizerArgsChecked = true;
return SanArgs;
}
const XRayArgs& ToolChain::getXRayArgs() const {

View File

@ -63,7 +63,9 @@ public:
return ParseInlineAsmUsingAsmParser;
}
bool isPICDefault() const override { return true; }
bool isPIEDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool isPICDefaultForced() const override { return true; }
void

View File

@ -67,7 +67,9 @@ public:
bool useIntegratedAs() const override { return true; }
bool isCrossCompiling() const override { return true; }
bool isPICDefault() const override { return false; }
bool isPIEDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }

View File

@ -42,7 +42,9 @@ public:
bool useIntegratedAs() const override { return true; }
bool isCrossCompiling() const override { return true; }
bool isPICDefault() const override { return false; }
bool isPIEDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }

View File

@ -750,7 +750,7 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
const Driver &D, const InputInfo &Output,
const ArgList &Args,
const ArgList &Args, SanitizerArgs &SanArgs,
ArgStringList &CmdArgs) {
auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate,
@ -924,7 +924,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
else if (Val != "single")
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
} else if (TC.getSanitizerArgs().needsTsanRt()) {
} else if (SanArgs.needsTsanRt()) {
CmdArgs.push_back("-fprofile-update=atomic");
}
@ -5201,12 +5201,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// This is a coarse approximation of what llvm-gcc actually does, both
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
// complicated ways.
bool AsyncUnwindTables =
Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
(TC.IsUnwindTablesDefault(Args) ||
TC.getSanitizerArgs().needsUnwindTables()) &&
!Freestanding);
auto SanitizeArgs = TC.getSanitizerArgs(Args);
bool AsyncUnwindTables = Args.hasFlag(
options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
(TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) &&
!Freestanding);
bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables,
options::OPT_fno_unwind_tables, false);
if (AsyncUnwindTables)
@ -5447,7 +5447,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// for sampling, overhead of call arc collection is way too high and there's
// no way to collect the output.
if (!Triple.isNVPTX() && !Triple.isAMDGCN())
addPGOAndCoverageFlags(TC, C, D, Output, Args, CmdArgs);
addPGOAndCoverageFlags(TC, C, D, Output, Args, SanitizeArgs, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ);
@ -5455,7 +5455,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (RawTriple.isPS4CPU() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
PS4cpu::addProfileRTArgs(TC, Args, CmdArgs);
PS4cpu::addSanitizerArgs(TC, CmdArgs);
PS4cpu::addSanitizerArgs(TC, Args, CmdArgs);
}
// Pass options for controlling the default header search paths.
@ -5926,8 +5926,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-openmp-extensions");
}
const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
Sanitize.addArgs(TC, Args, CmdArgs, InputType);
SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType);
const XRayArgs &XRay = TC.getXRayArgs();
XRay.addArgs(TC, Args, CmdArgs, InputType);
@ -6871,12 +6870,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
bool DefaultsSplitLTOUnit =
(WholeProgramVTables || Sanitize.needsLTO()) &&
(WholeProgramVTables || SanitizeArgs.needsLTO()) &&
(LTOMode == LTOK_Full || TC.canSplitThinLTOUnit());
bool SplitLTOUnit =
Args.hasFlag(options::OPT_fsplit_lto_unit,
options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit);
if (Sanitize.needsLTO() && !SplitLTOUnit)
if (SanitizeArgs.needsLTO() && !SplitLTOUnit)
D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-split-lto-unit"
<< "-fsanitize=cfi";
if (SplitLTOUnit)

View File

@ -47,7 +47,7 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--no-dynamic-linker");
// Provide PIE linker flags in case PIE is default for the architecture.
if (ToolChain.isPIEDefault()) {
if (ToolChain.isPIEDefault(Args)) {
CmdArgs.push_back("-pie");
CmdArgs.push_back("-zrelro");
}
@ -125,7 +125,7 @@ Tool *CloudABI::buildLinker() const {
return new tools::cloudabi::Linker(*this);
}
bool CloudABI::isPIEDefault() const {
bool CloudABI::isPIEDefault(const llvm::opt::ArgList &Args) const {
// Only enable PIE on architectures that support PC-relative
// addressing. PC-relative addressing is required, as the process
// startup code must be able to relocate itself.

View File

@ -55,7 +55,7 @@ public:
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
SanitizerMask getDefaultSanitizers() const override;

View File

@ -787,7 +787,7 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
SmallVectorImpl<StringRef> &NonWholeStaticRuntimes,
SmallVectorImpl<StringRef> &HelperStaticRuntimes,
SmallVectorImpl<StringRef> &RequiredSymbols) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
// Collect shared runtimes.
if (SanArgs.needsSharedRt()) {
if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) {
@ -923,7 +923,7 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
NonWholeStaticRuntimes, HelperStaticRuntimes,
RequiredSymbols);
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
// Inject libfuzzer dependencies.
if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() &&
!Args.hasArg(options::OPT_shared)) {
@ -1116,7 +1116,7 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple();
const llvm::Triple &Triple = ToolChain.getTriple();
bool PIE = ToolChain.isPIEDefault();
bool PIE = ToolChain.isPIEDefault(Args);
bool PIC = PIE || ToolChain.isPICDefault();
// The Darwin/MachO default to use PIC does not apply when using -static.
if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static))

View File

@ -185,7 +185,7 @@ void tools::CrossWindows::Linker::ConstructJob(
}
}
if (TC.getSanitizerArgs().needsAsanRt()) {
if (TC.getSanitizerArgs(Args).needsAsanRt()) {
// TODO handle /MT[d] /MD[d]
if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
@ -223,7 +223,7 @@ bool CrossWindowsToolChain::isPICDefault() const {
return getArch() == llvm::Triple::x86_64;
}
bool CrossWindowsToolChain::isPIEDefault() const {
bool CrossWindowsToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
return getArch() == llvm::Triple::x86_64;
}

View File

@ -57,7 +57,7 @@ public:
bool IsIntegratedAssemblerDefault() const override { return true; }
bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
LangOptions::StackProtectorMode

View File

@ -157,7 +157,9 @@ public:
bool useIntegratedAs() const override { return false; }
bool isCrossCompiling() const override { return true; }
bool isPICDefault() const override { return false; }
bool isPIEDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }
bool supportsDebugInfoOption(const llvm::opt::Arg *A) const override;

View File

@ -1357,7 +1357,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
return;
}
const SanitizerArgs &Sanitize = getSanitizerArgs();
const SanitizerArgs &Sanitize = getSanitizerArgs(Args);
if (Sanitize.needsAsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
if (Sanitize.needsLsanRt())
@ -2783,7 +2783,7 @@ bool Darwin::SupportsEmbeddedBitcode() const {
bool MachO::isPICDefault() const { return true; }
bool MachO::isPIEDefault() const { return false; }
bool MachO::isPIEDefault(const llvm::opt::ArgList &Args) const { return false; }
bool MachO::isPICDefaultForced() const {
return (getArch() == llvm::Triple::x86_64 ||

View File

@ -254,7 +254,7 @@ public:
}
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
bool SupportsProfiling() const override;

View File

@ -145,7 +145,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
(Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
(Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault(Args));
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
@ -467,7 +467,9 @@ bool FreeBSD::HasNativeLLVMSupport() const { return true; }
bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; }
bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const {
return getSanitizerArgs(Args).requiresPIE();
}
SanitizerMask FreeBSD::getSupportedSanitizers() const {
const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64;

View File

@ -74,7 +74,7 @@ public:
llvm::ExceptionHandling
GetExceptionModel(const llvm::opt::ArgList &Args) const override;
bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
unsigned GetDefaultDwarfVersion() const override;
// Until dtrace (via CTF) and LLDB can deal with distributed debug info,

View File

@ -91,7 +91,7 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
else if (Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-shared");
const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs();
const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);
if (!Args.hasArg(options::OPT_shared)) {
std::string Dyld = D.DyldPrefix;
@ -256,8 +256,9 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
addMultilibFlag(
Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true),
"fexceptions", Flags);
addMultilibFlag(getSanitizerArgs().needsAsanRt(), "fsanitize=address", Flags);
addMultilibFlag(getSanitizerArgs().needsHwasanRt(), "fsanitize=hwaddress",
addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address",
Flags);
addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress",
Flags);
addMultilibFlag(

View File

@ -54,7 +54,9 @@ public:
return true;
}
bool isPICDefault() const override { return false; }
bool isPIEDefault() const override { return true; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return true;
}
bool isPICDefaultForced() const override { return false; }
llvm::DebuggerKind getDefaultDebuggerTuning() const override {
return llvm::DebuggerKind::GDB;

View File

@ -312,7 +312,7 @@ static bool getPIE(const ArgList &Args, const ToolChain &TC) {
Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie,
options::OPT_nopie);
if (!A)
return TC.isPIEDefault();
return TC.isPIEDefault(Args);
return A->getOption().matches(options::OPT_pie);
}
@ -2723,7 +2723,9 @@ bool Generic_GCC::isPICDefault() const {
}
}
bool Generic_GCC::isPIEDefault() const { return false; }
bool Generic_GCC::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}
bool Generic_GCC::isPICDefaultForced() const {
return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows();

View File

@ -298,7 +298,7 @@ public:
bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
bool IsIntegratedAssemblerDefault() const override;
llvm::opt::DerivedArgList *

View File

@ -16,6 +16,7 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@ -37,6 +38,42 @@ namespace {
const unsigned HIPCodeObjectAlign = 4096;
} // namespace
static bool shouldSkipSanitizeOption(const ToolChain &TC,
const llvm::opt::ArgList &DriverArgs,
StringRef TargetID,
const llvm::opt::Arg *A) {
// For actions without targetID, do nothing.
if (TargetID.empty())
return false;
Option O = A->getOption();
if (!O.matches(options::OPT_fsanitize_EQ))
return false;
if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
-options::OPT_fno_gpu_sanitize))
return true;
auto &Diags = TC.getDriver().getDiags();
// For simplicity, we only allow -fsanitize=address
SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false);
if (K != SanitizerKind::Address)
return true;
llvm::StringMap<bool> FeatureMap;
auto OptionalGpuArch = parseTargetID(TC.getTriple(), TargetID, &FeatureMap);
assert(OptionalGpuArch && "Invalid Target ID");
auto Loc = FeatureMap.find("xnack");
if (Loc == FeatureMap.end() || !Loc->second) {
Diags.Report(
clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature)
<< A->getAsString(DriverArgs) << TargetID << "xnack+";
return true;
}
return false;
}
void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const InputInfo &Output,
@ -86,12 +123,6 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
for (auto Input : Inputs)
LldArgs.push_back(Input.getFilename());
if (Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
false))
llvm::for_each(TC.getHIPDeviceLibs(Args), [&](auto BCFile) {
LldArgs.push_back(Args.MakeArgString(BCFile.Path));
});
const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
Lld, LldArgs, Inputs, Output));
@ -237,6 +268,14 @@ HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple,
// Lookup binaries into the driver directory, this is used to
// discover the clang-offload-bundler executable.
getProgramPaths().push_back(getDriver().Dir);
// Diagnose unsupported sanitizer options only once.
for (auto A : Args.filtered(options::OPT_fsanitize_EQ)) {
SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false);
if (K != SanitizerKind::Address)
D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target)
<< A->getAsString(Args) << getTriple().str();
}
}
void HIPToolChain::addClangTargetOptions(
@ -295,7 +334,8 @@ HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
const OptTable &Opts = getDriver().getOpts();
for (Arg *A : Args) {
if (!shouldSkipArgument(A))
if (!shouldSkipArgument(A) &&
!shouldSkipSanitizeOption(*this, Args, BoundArch, A))
DAL->append(A);
}
@ -399,7 +439,8 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
// If --hip-device-lib is not set, add the default bitcode libraries.
if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
options::OPT_fno_gpu_sanitize, false)) {
options::OPT_fno_gpu_sanitize) &&
getSanitizerArgs(DriverArgs).needsAsanRt()) {
auto AsanRTL = RocmInstallation.getAsanRTLPath();
if (AsanRTL.empty()) {
unsigned DiagID = getDriver().getDiags().getCustomDiagID(
@ -439,22 +480,6 @@ void HIPToolChain::checkTargetID(const llvm::opt::ArgList &DriverArgs) const {
if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) {
getDriver().Diag(clang::diag::err_drv_bad_target_id)
<< PTID.OptionalTargetID.getValue();
return;
}
assert(PTID.OptionalFeatures && "Invalid return from getParsedTargetID");
auto &FeatureMap = PTID.OptionalFeatures.getValue();
// Sanitizer is not supported with xnack-.
if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
options::OPT_fno_gpu_sanitize, false)) {
auto Loc = FeatureMap.find("xnack");
if (Loc != FeatureMap.end() && !Loc->second) {
auto &Diags = getDriver().getDiags();
auto DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error,
"'-fgpu-sanitize' is not compatible with offload arch '%0'. "
"Use an offload arch without 'xnack-' instead");
Diags.Report(DiagID) << PTID.OptionalTargetID.getValue();
}
}
return;
}

View File

@ -22,7 +22,7 @@ public:
Haiku(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
bool isPIEDefault() const override {
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return getTriple().getArch() == llvm::Triple::x86_64;
}

View File

@ -662,9 +662,9 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
}
}
bool Linux::isPIEDefault() const {
bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const {
return getTriple().isAndroid() || getTriple().isMusl() ||
getSanitizerArgs().requiresPIE();
getSanitizerArgs(Args).requiresPIE();
}
bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const {

View File

@ -43,7 +43,7 @@ public:
CXXStdlibType GetDefaultCXXStdlibType() const override;
bool
IsAArch64OutlineAtomicsDefault(const llvm::opt::ArgList &Args) const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isNoExecStackDefault() const override;
bool IsMathErrnoDefault() const override;
SanitizerMask getSupportedSanitizers() const override;

View File

@ -37,7 +37,9 @@ public:
Action::OffloadKind) const override;
bool isPICDefault() const override { return false; }
bool isPIEDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool isPICDefaultForced() const override { return true; }
UnwindLibType

View File

@ -530,7 +530,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
}
if (TC.getSanitizerArgs().needsFuzzer()) {
if (TC.getSanitizerArgs(Args).needsFuzzer()) {
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back(
Args.MakeArgString(std::string("-wholearchive:") +
@ -541,10 +541,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
}
if (TC.getSanitizerArgs().needsAsanRt()) {
if (TC.getSanitizerArgs(Args).needsAsanRt()) {
CmdArgs.push_back(Args.MakeArgString("-debug"));
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
if (TC.getSanitizerArgs().needsSharedRt() ||
if (TC.getSanitizerArgs(Args).needsSharedRt() ||
Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
@ -799,7 +799,7 @@ bool MSVCToolChain::isPICDefault() const {
getArch() == llvm::Triple::aarch64;
}
bool MSVCToolChain::isPIEDefault() const {
bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}

View File

@ -52,7 +52,7 @@ public:
bool IsIntegratedAssemblerDefault() const override;
bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
/// Set CodeView as the default debug info format for non-MachO binary

View File

@ -98,7 +98,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const ToolChain &TC = getToolChain();
const Driver &D = TC.getDriver();
const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args);
ArgStringList CmdArgs;
@ -482,7 +482,9 @@ bool toolchains::MinGW::isPICDefault() const {
getArch() == llvm::Triple::aarch64;
}
bool toolchains::MinGW::isPIEDefault() const { return false; }
bool toolchains::MinGW::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}
bool toolchains::MinGW::isPICDefaultForced() const {
return getArch() == llvm::Triple::x86_64 ||

View File

@ -68,7 +68,7 @@ public:
bool IsIntegratedAssemblerDefault() const override;
bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
SanitizerMask getSupportedSanitizers() const override;

View File

@ -264,7 +264,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs();
const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);
if (SanArgs.needsSharedRt()) {
CmdArgs.push_back("-rpath");
CmdArgs.push_back(Args.MakeArgString(ToolChain.getCompilerRTPath()));
@ -501,7 +501,7 @@ SanitizerMask NetBSD::getSupportedSanitizers() const {
void NetBSD::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args,
Action::OffloadKind) const {
const SanitizerArgs &SanArgs = getSanitizerArgs();
const SanitizerArgs &SanArgs = getSanitizerArgs(DriverArgs);
if (SanArgs.hasAnySanitizer())
CC1Args.push_back("-D_REENTRANT");

View File

@ -59,7 +59,9 @@ public:
bool IsMathErrnoDefault() const override { return false; }
bool IsObjCNonFragileABIDefault() const override { return true; }
bool isPIEDefault() const override { return true; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return true;
}
RuntimeLibType GetDefaultRuntimeLibType() const override {
return ToolChain::RLT_CompilerRT;

View File

@ -71,8 +71,9 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}
static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
static void AddPS4SanitizerArgs(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
if (SanArgs.needsUbsanRt()) {
CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak");
}
@ -81,9 +82,9 @@ static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
}
}
void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC,
void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
if (SanArgs.needsUbsanRt())
CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a");
if (SanArgs.needsAsanRt())
@ -127,7 +128,7 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
AddPS4SanitizerArgs(ToolChain, CmdArgs);
AddPS4SanitizerArgs(ToolChain, Args, CmdArgs);
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);

View File

@ -23,7 +23,8 @@ namespace PS4cpu {
void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
void addSanitizerArgs(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs);
void addSanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
public:

View File

@ -34,7 +34,9 @@ bool TCEToolChain::IsMathErrnoDefault() const { return true; }
bool TCEToolChain::isPICDefault() const { return false; }
bool TCEToolChain::isPIEDefault() const { return false; }
bool TCEToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}
bool TCEToolChain::isPICDefaultForced() const { return false; }

View File

@ -27,7 +27,7 @@ public:
bool IsMathErrnoDefault() const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
};

View File

@ -53,7 +53,9 @@ Tool *VEToolChain::buildLinker() const {
bool VEToolChain::isPICDefault() const { return false; }
bool VEToolChain::isPIEDefault() const { return false; }
bool VEToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}
bool VEToolChain::isPICDefaultForced() const { return false; }

View File

@ -28,7 +28,7 @@ protected:
public:
bool IsIntegratedAssemblerDefault() const override { return true; }
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
bool SupportsProfiling() const override;
bool hasBlocksRuntime() const override;

View File

@ -201,7 +201,9 @@ bool WebAssembly::UseObjCMixedDispatch() const { return true; }
bool WebAssembly::isPICDefault() const { return false; }
bool WebAssembly::isPIEDefault() const { return false; }
bool WebAssembly::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}
bool WebAssembly::isPICDefaultForced() const { return false; }

View File

@ -45,7 +45,7 @@ private:
bool IsObjCNonFragileABIDefault() const override;
bool UseObjCMixedDispatch() const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
bool IsIntegratedAssemblerDefault() const override;
bool hasBlocksRuntime() const override;

View File

@ -102,7 +102,9 @@ Tool *XCoreToolChain::buildLinker() const {
bool XCoreToolChain::isPICDefault() const { return false; }
bool XCoreToolChain::isPIEDefault() const { return false; }
bool XCoreToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}
bool XCoreToolChain::isPICDefaultForced() const { return false; }

View File

@ -58,7 +58,7 @@ protected:
public:
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
bool SupportsProfiling() const override;
bool hasBlocksRuntime() const override;

View File

@ -23,7 +23,9 @@ public:
~ZOS() override;
bool isPICDefault() const override { return false; }
bool isPIEDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool isPICDefaultForced() const override { return false; }
bool IsIntegratedAssemblerDefault() const override { return true; }

View File

@ -1,47 +1,67 @@
// REQUIRES: clang-driver, x86-registered-target, amdgpu-registered-target
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900 \
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900:xnack+ \
// RUN: -fsanitize=address \
// RUN: -nogpuinc --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck %s
// RUN: %s 2>&1 | FileCheck -check-prefixes=NORDC %s
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900 \
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900:xnack+ \
// RUN: -fsanitize=address -fno-gpu-sanitize \
// RUN: -nogpuinc --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck %s
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900 \
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900:xnack+ \
// RUN: -fsanitize=address -fgpu-sanitize \
// RUN: -nogpuinc --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck -check-prefixes=NORDC %s
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900 \
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900:xnack+ \
// RUN: -fsanitize=address -fgpu-sanitize -fgpu-rdc \
// RUN: -nogpuinc --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck -check-prefixes=RDC %s
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900 \
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900:xnack+ \
// RUN: -fsanitize=address -fgpu-sanitize \
// RUN: -nogpuinc --rocm-path=%S/Inputs/rocm-invalid \
// RUN: %s 2>&1 | FileCheck -check-prefixes=FAIL %s
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900:xnack- \
// RUN: -fsanitize=address -fgpu-sanitize \
// RUN: -nogpuinc --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck -check-prefix=XNACK %s
// RUN: --offload-arch=gfx900:xnack+ --offload-arch=gfx906 -fsanitize=address -fgpu-sanitize \
// RUN: -fsanitize=leak -nogpuinc --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck -check-prefixes=XNACK %s
// RUN: %clang -### -target x86_64-unknown-linux-gnu --offload-arch=gfx900:xnack- \
// RUN: --offload-arch=gfx900:xnack+ --offload-arch=gfx906 -fsanitize=address -fgpu-sanitize \
// RUN: -fsanitize=leak -nogpuinc --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck -check-prefixes=XNACKNEG %s
// CHECK-NOT: {{"[^"]*clang[^"]*".* "-fcuda-is-device".* "-fsanitize=address"}}
// CHECK-NOT: {{"[^"]*clang[^"]*".* "-fcuda-is-device".* "-mlink-bitcode-file" ".*asanrtl.bc"}}
// CHECK-NOT: {{"[^"]*lld(\.exe){0,1}".* ".*hip.bc"}}
// CHECK: {{"[^"]*clang[^"]*".* "-triple" "x86_64-unknown-linux-gnu".* "-fsanitize=address"}}
// NORDC: {{"[^"]*clang[^"]*".* "-emit-obj".* "-fcuda-is-device".* "-mlink-bitcode-file" ".*asanrtl.bc".* "-mlink-builtin-bitcode" ".*hip.bc".* "-fsanitize=address".*}} "-o" "[[OUT:[^"]*.o]]"
// NORDC: {{"[^"]*lld(\.exe){0,1}".*}} "[[OUT]]" {{".*asanrtl.bc" ".*hip.bc"}}
// NORDC-NOT: {{"[^"]*lld(\.exe){0,1}".*}} "[[OUT]]" {{".*asanrtl.bc" ".*hip.bc"}}
// NORDC: {{"[^"]*clang[^"]*".* "-triple" "x86_64-unknown-linux-gnu".* "-fsanitize=address"}}
// RDC: {{"[^"]*clang[^"]*".* "-triple" "x86_64-unknown-linux-gnu".* "-fsanitize=address"}}
// RDC: {{"[^"]*clang[^"]*".* "-emit-llvm-bc".* "-fcuda-is-device".* "-fsanitize=address".*}} "-o" "[[OUT:[^"]*.bc]]"
// RDC: {{"[^"]*lld(\.exe){0,1}".*}} "[[OUT]]" {{".*asanrtl.bc" ".*hip.bc"}}
// RDC: {{"[^"]*clang[^"]*".* "-emit-llvm-bc".* "-fcuda-is-device".* "-mlink-bitcode-file" ".*asanrtl.bc".* "-mlink-builtin-bitcode" ".*hip.bc".* "-fsanitize=address".*}} "-o" "[[OUT:[^"]*.bc]]"
// RDC-NOT: {{"[^"]*lld(\.exe){0,1}".*}} "[[OUT]]" {{".*asanrtl.bc" ".*hip.bc"}}
// FAIL: AMDGPU address sanitizer runtime library (asanrtl) is not found. Please install ROCm device library which supports address sanitizer
// XNACK: error: '-fgpu-sanitize' is not compatible with offload arch 'gfx900:xnack-'. Use an offload arch without 'xnack-' instead
// XNACK-DAG: warning: ignoring '-fsanitize=leak' option as it is not currently supported for target 'amdgcn-amd-amdhsa'
// XNACK-DAG: warning: ignoring '-fsanitize=address' option as it is not currently supported for offload arch 'gfx900:xnack-'. Use it with an offload arch containing 'xnack+' instead
// XNACK-DAG: warning: ignoring '-fsanitize=address' option as it is not currently supported for offload arch 'gfx906'. Use it with an offload arch containing 'xnack+' instead
// XNACK-DAG: {{"[^"]*clang[^"]*".* "-mlink-bitcode-file" ".*asanrtl.bc".* "-target-cpu" "gfx900".* "-target-feature" "\+xnack".* "-fsanitize=address"}}
// XNACK-DAG: {{"[^"]*clang[^"]*".* "-target-cpu" "gfx900".* "-target-feature" "-xnack"}}
// XNACK-DAG: {{"[^"]*clang[^"]*".* "-target-cpu" "gfx906"}}
// XNACK-DAG: {{"[^"]*clang[^"]*".* "-triple" "x86_64-unknown-linux-gnu".* "-fsanitize=address,leak"}}
// XNACKNEG-NOT: {{"[^"]*clang[^"]*".* "-target-cpu" "gfx900".* "-target-feature" "+xnack".* "-fsanitize=address,leak"}}
// XNACKNEG-NOT: {{"[^"]*clang[^"]*".* "-target-cpu" "gfx900".* "-target-feature" "-xnack".* "-fsanitize=address,leak"}}
// XNACKNEG-NOT: {{"[^"]*clang[^"]*".* "-target-cpu" "gfx906".* "-fsanitize=address,leak"}}
// XNACKNEG-NOT: {{"[^"]*clang[^"]*".* "-target-cpu" "gfx900".* "-target-feature" "-xnack".* "-fsanitize=address"}}
// XNACKNEG-NOT: {{"[^"]*clang[^"]*".* "-target-cpu" "gfx906".* "-fsanitize=address"}}
// XNACKNEG-NOT: {{"[^"]*clang[^"]*".* "-mlink-bitcode-file" ".*asanrtl.bc".* "-target-cpu" "gfx900".* "-target-feature" "-xnack"}}
// XNACKNEG-NOT: {{"[^"]*clang[^"]*".* "-mlink-bitcode-file" ".*asanrtl.bc".* "-target-cpu" "gfx906"}}
// XNACKNEG-NOT: {{"[^"]*lld(\.exe){0,1}".* ".*hip.bc"}}