This flag can't be used at the same time as any of the other sanitizers. We add an equivalent flag to -static-libasan in -static-libhwasan to ensure static linking. gcc/ChangeLog: 2019-09-06 Matthew Malcomson * common.opt (static-libhwasan): New cli option. * config/gnu-user.h (LIBHWASAN_EARLY_SPEC): hwasan equivalent of asan command line flags. * flag-types.h (enum sanitize_code): SANITIZE_HWADDRESS member. * gcc.c (STATIC_LIBHWASAN_LIBS): New macro. (LIBHWASAN_SPEC): New macro. (LIBHWASAN_EARLY_SPEC): New macro. (SANITIZER_EARLY_SPEC): Update to include hwasan. (SANITIZER_SPEC): Update to include hwasan. (sanitize_spec_function): Use hwasan. * opts.c (finish_options): Add conflict between hwasan and tsan, also between hwasan and asan. (sanitizer_opts): New option structure for -fsanitize=hwaddress. ############### Attachment also inlined for ease of reply ############### diff --git a/gcc/common.opt b/gcc/common.opt index d342c4f3749a39df086236162636f14f91bcd8a0..527aada305097b54c927fd094e3ab82220459c2c 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -3273,6 +3273,9 @@ Driver static-libasan Driver +static-libhwasan +Driver + static-libtsan Driver diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h index 055a4f0afeca4a6339fd156db1bf1daf1aae0994..1e4b921afb62f22892aee0ca37e96983112a8134 100644 --- a/gcc/config/gnu-user.h +++ b/gcc/config/gnu-user.h @@ -129,14 +129,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* Link -lasan early on the command line. For -static-libasan, don't link it for -shared link, the executable should be compiled with -static-libasan in that case, and for executable link with --{,no-}whole-archive around - it to force everything into the executable. And similarly for -ltsan - and -llsan. */ + it to force everything into the executable. And similarly for -ltsan, + -lhwasan, and -llsan. */ #if defined(HAVE_LD_STATIC_DYNAMIC) #undef LIBASAN_EARLY_SPEC #define LIBASAN_EARLY_SPEC "%{!shared:libasan_preinit%O%s} " \ "%{static-libasan:%{!shared:" \ LD_STATIC_OPTION " --whole-archive -lasan --no-whole-archive " \ LD_DYNAMIC_OPTION "}}%{!static-libasan:-lasan}" +#undef LIBHWASAN_EARLY_SPEC +#define LIBHWASAN_EARLY_SPEC "%{static-libhwasan:%{!shared:" \ + LD_STATIC_OPTION " --whole-archive -lhwasan --no-whole-archive " \ + LD_DYNAMIC_OPTION "}}%{!static-libhwasan:-lhwasan}" #undef LIBTSAN_EARLY_SPEC #define LIBTSAN_EARLY_SPEC "%{!shared:libtsan_preinit%O%s} " \ "%{static-libtsan:%{!shared:" \ diff --git a/gcc/flag-types.h b/gcc/flag-types.h index a2103282d469db31ad157a87572068d943061c8c..fcc3dd45862b1b64b38a13702f7840ba461aea20 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -256,6 +256,7 @@ enum sanitize_code { SANITIZE_BUILTIN = 1UL << 25, SANITIZE_POINTER_COMPARE = 1UL << 26, SANITIZE_POINTER_SUBTRACT = 1UL << 27, + SANITIZE_HWADDRESS = 1UL << 28, SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT, SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN diff --git a/gcc/gcc.c b/gcc/gcc.c index 7ebdf1f225b49769af3047c852ad3b72d6912fc0..c3d939af1a0fac87a8de95dff3960f2175aecf6d 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -708,6 +708,24 @@ proper position among the other output files. */ #define LIBASAN_EARLY_SPEC "" #endif +#ifndef LIBHWASAN_SPEC +#define STATIC_LIBHWASAN_LIBS \ + " %{static-libhwasan|static:%:include(libsanitizer.spec)%(link_libhwasan)}" +#ifdef LIBHWASAN_EARLY_SPEC +#define LIBHWASAN_SPEC STATIC_LIBHWASAN_LIBS +#elif defined(HAVE_LD_STATIC_DYNAMIC) +#define LIBHWASAN_SPEC "%{static-libhwasan:" LD_STATIC_OPTION \ + "} -lhwasan %{static-libhwasan:" LD_DYNAMIC_OPTION "}" \ + STATIC_LIBHWASAN_LIBS +#else +#define LIBHWASAN_SPEC "-lhwasan" STATIC_LIBHWASAN_LIBS +#endif +#endif + +#ifndef LIBHWASAN_EARLY_SPEC +#define LIBHWASAN_EARLY_SPEC "" +#endif + #ifndef LIBTSAN_SPEC #define STATIC_LIBTSAN_LIBS \ " %{static-libtsan|static:%:include(libsanitizer.spec)%(link_libtsan)}" @@ -982,6 +1000,7 @@ proper position among the other output files. */ #ifndef SANITIZER_EARLY_SPEC #define SANITIZER_EARLY_SPEC "\ %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \ + %{%:sanitize(hwaddress):" LIBHWASAN_EARLY_SPEC "} \ %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \ %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}}" #endif @@ -991,6 +1010,8 @@ proper position among the other output files. */ #define SANITIZER_SPEC "\ %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\ %{static:%ecannot specify -static with -fsanitize=address}}\ + %{%:sanitize(hwaddress):" LIBHWASAN_SPEC "\ + %{static:%ecannot specify -static with -fsanitize=hwaddress}}\ %{%:sanitize(thread):" LIBTSAN_SPEC "\ %{static:%ecannot specify -static with -fsanitize=thread}}\ %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\ @@ -9387,6 +9408,8 @@ sanitize_spec_function (int argc, const char **argv) if (strcmp (argv[0], "address") == 0) return (flag_sanitize & SANITIZE_USER_ADDRESS) ? "" : NULL; + if (strcmp (argv[0], "hwaddress") == 0) + return (flag_sanitize & SANITIZE_HWADDRESS) ? "" : NULL; if (strcmp (argv[0], "kernel-address") == 0) return (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ? "" : NULL; if (strcmp (argv[0], "thread") == 0) diff --git a/gcc/opts.c b/gcc/opts.c index 879ab17c3620ca6e002b46f4f833ed2b4c0f5432..aedb1db6c00a139f575a341559006d9c3871d233 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1174,6 +1174,20 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, error_at (loc, "%<-fsanitize=leak%> is incompatible with %<-fsanitize=thread%>"); + /* HWASan and ASan conflict with each other. */ + if ((opts->x_flag_sanitize & SANITIZE_ADDRESS) + && (opts->x_flag_sanitize & SANITIZE_HWADDRESS)) + error_at (loc, + "%<-fsanitize=hwaddress%> is incompatible with both" + "%<-fsanitize=address%> and %<-fsanitize=kernel-address%>"); + + /* And with TSan. */ + if ((opts->x_flag_sanitize & SANITIZE_HWADDRESS) + && (opts->x_flag_sanitize & SANITIZE_THREAD)) + error_at (loc, + "%<-fsanitize=hwaddress%> is incompatible with " + "%<-fsanitize=thread%>"); + /* Check error recovery for -fsanitize-recover option. */ for (int i = 0; sanitizer_opts[i].name != NULL; ++i) if ((opts->x_flag_sanitize_recover & sanitizer_opts[i].flag) @@ -1193,7 +1207,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, /* Enable -fsanitize-address-use-after-scope if address sanitizer is enabled. */ - if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS) + if (((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS) + || (opts->x_flag_sanitize & SANITIZE_HWADDRESS)) && !opts_set->x_flag_sanitize_address_use_after_scope) opts->x_flag_sanitize_address_use_after_scope = true; @@ -1752,6 +1767,8 @@ const struct sanitizer_opts_s sanitizer_opts[] = #define SANITIZER_OPT(name, flags, recover) \ { #name, flags, sizeof #name - 1, recover } SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true), + // TODO Look into this properly + SANITIZER_OPT (hwaddress, (SANITIZE_HWADDRESS), false), SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS), true), SANITIZER_OPT (pointer-compare, SANITIZE_POINTER_COMPARE, true),