[cfe-commits] [PATCH] Refactor -fsanitize arguments parsing: provide a more careful diagnostic.
Alexey Samsonov
samsonov at google.com
Tue Nov 27 22:24:35 PST 2012
Hi rsmith,
This patch improves diagnostic messages printed for invalid
sets of values in -fsanitize= flags. See regression test diff for
examples.
http://llvm-reviews.chandlerc.com/D143
Files:
test/Driver/fsanitize.c
lib/Driver/Tools.cpp
lib/Driver/SanitizerArgs.h
Index: test/Driver/fsanitize.c
===================================================================
--- test/Driver/fsanitize.c
+++ test/Driver/fsanitize.c
@@ -15,6 +15,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
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -1456,51 +1456,13 @@
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,10 @@
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,
+ Kind & (NeedsAsan ? NeedsAsanRt : NeedsTsanRt))
+ << lastArgumentForKind(D, Args,
+ Kind & (NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt));
}
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
Index: lib/Driver/SanitizerArgs.h
===================================================================
--- lib/Driver/SanitizerArgs.h
+++ lib/Driver/SanitizerArgs.h
@@ -71,18 +71,77 @@
/// 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);
+ }
+ 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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D143.1.patch
Type: text/x-patch
Size: 8205 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20121127/c93865e3/attachment.bin>
More information about the cfe-commits
mailing list