Refactor -fsanitize, -f*-sanitizer arguments parsing. Provide a more careful diagnostic for invalid sets of sanitizers
llvm-svn: 168794
This commit is contained in:
parent
df5f3028e2
commit
53f7e12909
|
@ -71,18 +71,78 @@ class SanitizerArgs {
|
|||
|
||||
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
|
||||
/// invalid components.
|
||||
static unsigned parse(const Driver &D, const Arg *A) {
|
||||
static unsigned parse(const Driver &D, const Arg *A, bool DiagnoseErrors) {
|
||||
unsigned Kind = 0;
|
||||
for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
|
||||
if (unsigned K = parse(A->getValue(I)))
|
||||
Kind |= K;
|
||||
else
|
||||
else if (DiagnoseErrors)
|
||||
D.Diag(diag::err_drv_unsupported_option_argument)
|
||||
<< A->getOption().getName() << A->getValue(I);
|
||||
}
|
||||
return Kind;
|
||||
}
|
||||
|
||||
/// Parse a single flag of the form -f[no]sanitize=, or
|
||||
/// -f*-sanitizer. Sets the masks defining required change of Kind value.
|
||||
/// Returns true if the flag was parsed successfully.
|
||||
static bool parse(const Driver &D, const ArgList &Args, const Arg *A,
|
||||
unsigned &Add, unsigned &Remove, bool DiagnoseErrors) {
|
||||
Add = 0;
|
||||
Remove = 0;
|
||||
const char *DeprecatedReplacement = 0;
|
||||
if (A->getOption().matches(options::OPT_faddress_sanitizer)) {
|
||||
Add = Address;
|
||||
DeprecatedReplacement = "-fsanitize=address";
|
||||
} else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) {
|
||||
Remove = Address;
|
||||
DeprecatedReplacement = "-fno-sanitize=address";
|
||||
} else if (A->getOption().matches(options::OPT_fthread_sanitizer)) {
|
||||
Add = Thread;
|
||||
DeprecatedReplacement = "-fsanitize=thread";
|
||||
} else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) {
|
||||
Remove = Thread;
|
||||
DeprecatedReplacement = "-fno-sanitize=thread";
|
||||
} else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
|
||||
Add = Undefined;
|
||||
DeprecatedReplacement = "-fsanitize=undefined";
|
||||
} else if (A->getOption().matches(options::OPT_fbounds_checking) ||
|
||||
A->getOption().matches(options::OPT_fbounds_checking_EQ)) {
|
||||
Add = Bounds;
|
||||
DeprecatedReplacement = "-fsanitize=bounds";
|
||||
} else if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
|
||||
Add = parse(D, A, DiagnoseErrors);
|
||||
} else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
|
||||
Remove = parse(D, A, DiagnoseErrors);
|
||||
} else {
|
||||
// Flag is not relevant to sanitizers.
|
||||
return false;
|
||||
}
|
||||
// If this is a deprecated synonym, produce a warning directing users
|
||||
// towards the new spelling.
|
||||
if (DeprecatedReplacement && DiagnoseErrors)
|
||||
D.Diag(diag::warn_drv_deprecated_arg)
|
||||
<< A->getAsString(Args) << DeprecatedReplacement;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Produce an argument string from ArgList \p Args, which shows how it
|
||||
/// provides a sanitizer kind in \p Mask. For example, the argument list
|
||||
/// "-fsanitize=thread,vptr -faddress-sanitizer" with mask \c NeedsUbsanRt
|
||||
/// would produce "-fsanitize=vptr".
|
||||
static std::string lastArgumentForKind(const Driver &D, const ArgList &Args,
|
||||
unsigned Kind) {
|
||||
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
|
||||
I != E; ++I) {
|
||||
unsigned Add, Remove;
|
||||
if (parse(D, Args, *I, Add, Remove, false) &&
|
||||
(Add & Kind))
|
||||
return describeSanitizeArg(Args, *I, Kind);
|
||||
Kind &= ~Remove;
|
||||
}
|
||||
llvm_unreachable("arg list didn't provide expected value");
|
||||
}
|
||||
|
||||
/// Produce an argument string from argument \p A, which shows how it provides
|
||||
/// a value in \p Mask. For instance, the argument
|
||||
/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
|
||||
|
|
|
@ -1456,51 +1456,13 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
|
|||
SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) {
|
||||
Kind = 0;
|
||||
|
||||
const Arg *AsanArg, *TsanArg, *UbsanArg;
|
||||
for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
|
||||
unsigned Add = 0, Remove = 0;
|
||||
const char *DeprecatedReplacement = 0;
|
||||
if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) {
|
||||
Add = Address;
|
||||
DeprecatedReplacement = "-fsanitize=address";
|
||||
} else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) {
|
||||
Remove = Address;
|
||||
DeprecatedReplacement = "-fno-sanitize=address";
|
||||
} else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) {
|
||||
Add = Thread;
|
||||
DeprecatedReplacement = "-fsanitize=thread";
|
||||
} else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) {
|
||||
Remove = Thread;
|
||||
DeprecatedReplacement = "-fno-sanitize=thread";
|
||||
} else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
|
||||
Add = Undefined;
|
||||
DeprecatedReplacement = "-fsanitize=undefined";
|
||||
} else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) {
|
||||
Add = parse(D, *I);
|
||||
} else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) {
|
||||
Remove = parse(D, *I);
|
||||
} else if ((*I)->getOption().matches(options::OPT_fbounds_checking) ||
|
||||
(*I)->getOption().matches(options::OPT_fbounds_checking_EQ)) {
|
||||
Add = Bounds;
|
||||
DeprecatedReplacement = "-fsanitize=bounds";
|
||||
} else {
|
||||
unsigned Add, Remove;
|
||||
if (!parse(D, Args, *I, Add, Remove, true))
|
||||
continue;
|
||||
}
|
||||
|
||||
(*I)->claim();
|
||||
|
||||
Kind |= Add;
|
||||
Kind &= ~Remove;
|
||||
|
||||
if (Add & NeedsAsanRt) AsanArg = *I;
|
||||
if (Add & NeedsTsanRt) TsanArg = *I;
|
||||
if (Add & NeedsUbsanRt) UbsanArg = *I;
|
||||
|
||||
// If this is a deprecated synonym, produce a warning directing users
|
||||
// towards the new spelling.
|
||||
if (DeprecatedReplacement)
|
||||
D.Diag(diag::warn_drv_deprecated_arg)
|
||||
<< (*I)->getAsString(Args) << DeprecatedReplacement;
|
||||
}
|
||||
|
||||
// Only one runtime library can be used at once.
|
||||
|
@ -1510,10 +1472,8 @@ SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) {
|
|||
bool NeedsUbsan = needsUbsanRt();
|
||||
if (NeedsAsan + NeedsTsan + NeedsUbsan > 1)
|
||||
D.Diag(diag::err_drv_argument_not_allowed_with)
|
||||
<< describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg,
|
||||
NeedsAsan ? NeedsAsanRt : NeedsTsanRt)
|
||||
<< describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg,
|
||||
NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt);
|
||||
<< lastArgumentForKind(D, Args, NeedsAsan ? NeedsAsanRt : NeedsTsanRt)
|
||||
<< lastArgumentForKind(D, Args, NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt);
|
||||
}
|
||||
|
||||
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
// RUN: %clang -target x86_64-linux-gnu -faddress-sanitizer -fthread-sanitizer -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TSAN
|
||||
// CHECK-ASAN-TSAN: '-faddress-sanitizer' not allowed with '-fthread-sanitizer'
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize=alignment -fsanitize=vptr -fno-sanitize=vptr %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-ASAN
|
||||
// CHECK-UBSAN-ASAN: '-fsanitize=address' not allowed with '-fsanitize=alignment'
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-sanitize=vptr -fsanitize=undefined,address %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-UBSAN-ASAN
|
||||
// CHECK-VPTR-UBSAN-ASAN: '-fsanitize=address' not allowed with '-fsanitize=undefined'
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior -fthread-sanitizer -fno-thread-sanitizer -faddress-sanitizer -fno-address-sanitizer -fbounds-checking -c -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=CHECK-DEPRECATED
|
||||
// CHECK-DEPRECATED: argument '-fcatch-undefined-behavior' is deprecated, use '-fsanitize=undefined' instead
|
||||
// CHECK-DEPRECATED: argument '-fthread-sanitizer' is deprecated, use '-fsanitize=thread' instead
|
||||
|
|
Loading…
Reference in New Issue