libsanitizer: Add tests
authorMatthew Malcomson <matthew.malcomson@arm.com>
Wed, 25 Nov 2020 16:31:49 +0000 (16:31 +0000)
committerMatthew Malcomson <matthew.malcomson@arm.com>
Wed, 25 Nov 2020 16:39:09 +0000 (16:39 +0000)
Only interesting thing here is that we have to make sure the tagging mechanism
is deterministic to avoid flaky tests.

gcc/testsuite/ChangeLog:

* c-c++-common/ubsan/sanitize-recover-7.c: Update error message format.
* lib/asan-dg.exp (asan_link_flags): Implement as a helper
function asan_link_flags_1 which asan_link_flags and
hwasan_link_flags use.
(asan_link_flags_1): Parametrised version of asan_link_flags.
* c-c++-common/hwasan/aligned-alloc.c: New test.
* c-c++-common/hwasan/alloca-array-accessible.c: New test.
* c-c++-common/hwasan/alloca-base-init.c: New test.
* c-c++-common/hwasan/alloca-gets-different-tag.c: New test.
* c-c++-common/hwasan/alloca-outside-caught.c: New test.
* c-c++-common/hwasan/arguments-1.c: New test.
* c-c++-common/hwasan/arguments-2.c: New test.
* c-c++-common/hwasan/arguments-3.c: New test.
* c-c++-common/hwasan/arguments.c: New test.
* c-c++-common/hwasan/asan-pr63316.c: New test.
* c-c++-common/hwasan/asan-pr70541.c: New test.
* c-c++-common/hwasan/asan-pr78106.c: New test.
* c-c++-common/hwasan/asan-pr79944.c: New test.
* c-c++-common/hwasan/asan-rlimit-mmap-test-1.c: New test.
* c-c++-common/hwasan/bitfield-1.c: New test.
* c-c++-common/hwasan/bitfield-2.c: New test.
* c-c++-common/hwasan/builtin-special-handling.c: New test.
* c-c++-common/hwasan/check-interface.c: New test.
* c-c++-common/hwasan/halt_on_error-1.c: New test.
* c-c++-common/hwasan/handles-poly_int-marked-vars.c: New test.
* c-c++-common/hwasan/heap-overflow.c: New test.
* c-c++-common/hwasan/hwasan-poison-optimisation.c: New test.
* c-c++-common/hwasan/hwasan-thread-access-parent.c: New test.
* c-c++-common/hwasan/hwasan-thread-basic-failure.c: New test.
* c-c++-common/hwasan/hwasan-thread-clears-stack.c: New test.
* c-c++-common/hwasan/hwasan-thread-success.c: New test.
* c-c++-common/hwasan/kernel-defaults.c: New test.
* c-c++-common/hwasan/large-aligned-0.c: New test.
* c-c++-common/hwasan/large-aligned-1.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-0.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-1.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-2.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-3.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-4.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-5.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-6.c: New test.
* c-c++-common/hwasan/large-aligned-untagging-7.c: New test.
* c-c++-common/hwasan/macro-definition.c: New test.
* c-c++-common/hwasan/no-sanitize-attribute.c: New test.
* c-c++-common/hwasan/param-instrument-mem-intrinsics.c: New test.
* c-c++-common/hwasan/param-instrument-reads-and-writes.c: New test.
* c-c++-common/hwasan/param-instrument-reads.c: New test.
* c-c++-common/hwasan/param-instrument-writes.c: New test.
* c-c++-common/hwasan/random-frame-tag.c: New test.
* c-c++-common/hwasan/sanity-check-pure-c.c: New test.
* c-c++-common/hwasan/setjmp-longjmp-0.c: New test.
* c-c++-common/hwasan/setjmp-longjmp-1.c: New test.
* c-c++-common/hwasan/stack-tagging-basic-0.c: New test.
* c-c++-common/hwasan/stack-tagging-basic-1.c: New test.
* c-c++-common/hwasan/stack-tagging-disable.c: New test.
* c-c++-common/hwasan/unprotected-allocas-0.c: New test.
* c-c++-common/hwasan/unprotected-allocas-1.c: New test.
* c-c++-common/hwasan/use-after-free.c: New test.
* c-c++-common/hwasan/vararray-outside-caught.c: New test.
* c-c++-common/hwasan/vararray-stack-restore-correct.c: New test.
* c-c++-common/hwasan/very-large-objects.c: New test.
* g++.dg/hwasan/hwasan.exp: New test.
* g++.dg/hwasan/rvo-handled.C: New test.
* gcc.dg/hwasan/hwasan.exp: New test.
* gcc.dg/hwasan/nested-functions-0.c: New test.
* gcc.dg/hwasan/nested-functions-1.c: New test.
* gcc.dg/hwasan/nested-functions-2.c: New test.
* lib/hwasan-dg.exp: New file.

65 files changed:
gcc/testsuite/c-c++-common/hwasan/aligned-alloc.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/alloca-array-accessible.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/alloca-base-init.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/alloca-gets-different-tag.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/alloca-outside-caught.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/arguments-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/arguments-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/arguments-3.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/arguments.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/asan-pr63316.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/asan-pr70541.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/asan-pr78106.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/asan-pr79944.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/asan-rlimit-mmap-test-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/bitfield-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/bitfield-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/check-interface.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/halt_on_error-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/handles-poly_int-marked-vars.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/heap-overflow.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/hwasan-poison-optimisation.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/hwasan-thread-access-parent.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/hwasan-thread-basic-failure.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/hwasan-thread-success.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/kernel-defaults.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-0.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-0.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-3.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-5.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-6.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-7.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/macro-definition.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/no-sanitize-attribute.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/param-instrument-mem-intrinsics.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/param-instrument-reads-and-writes.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/param-instrument-reads.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/param-instrument-writes.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/random-frame-tag.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/sanity-check-pure-c.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-0.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-0.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/stack-tagging-disable.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-0.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/use-after-free.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/vararray-outside-caught.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/vararray-stack-restore-correct.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/hwasan/very-large-objects.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/ubsan/sanitize-recover-7.c
gcc/testsuite/g++.dg/hwasan/hwasan.exp [new file with mode: 0644]
gcc/testsuite/g++.dg/hwasan/rvo-handled.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/hwasan/hwasan.exp [new file with mode: 0644]
gcc/testsuite/gcc.dg/hwasan/nested-functions-0.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/hwasan/nested-functions-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/hwasan/nested-functions-2.c [new file with mode: 0644]
gcc/testsuite/lib/asan-dg.exp
gcc/testsuite/lib/hwasan-dg.exp [new file with mode: 0644]

diff --git a/gcc/testsuite/c-c++-common/hwasan/aligned-alloc.c b/gcc/testsuite/c-c++-common/hwasan/aligned-alloc.c
new file mode 100644 (file)
index 0000000..d38b1f3
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* This program fails at runtime in the libhwasan library.
+   The allocator can't handle the requested invalid alignment.  */
+
+int
+main ()
+{
+  void *p = __builtin_aligned_alloc (17, 100);
+  if (((unsigned long long)p & 0x10) == 0)
+    return 0;
+  return 1;
+}
+
+/* { dg-output "HWAddressSanitizer: invalid alignment requested in aligned_alloc: 17" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/alloca-array-accessible.c b/gcc/testsuite/c-c++-common/hwasan/alloca-array-accessible.c
new file mode 100644 (file)
index 0000000..5e4c168
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+#define alloca __builtin_alloca
+
+int __attribute__ ((noinline))
+using_alloca (int num)
+{
+  int retval = 0;
+  int *big_array = (int*)alloca (num * sizeof (int));
+  for (int i = 0; i < num; ++i) {
+      retval += big_array[i];
+  }
+  return retval;
+}
+
+int __attribute__ ((noinline))
+using_vararray (int num)
+{
+  int retval = 0;
+  int big_array[num];
+  for (int i = 0; i < num; ++i) {
+      retval += big_array[i];
+  }
+  return retval;
+}
+
+int main()
+{
+  using_alloca (16);
+  using_vararray (12);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/alloca-base-init.c b/gcc/testsuite/c-c++-common/hwasan/alloca-base-init.c
new file mode 100644 (file)
index 0000000..3ebeaa0
--- /dev/null
@@ -0,0 +1,66 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-additional-options "--param hwasan-random-frame-tag=1" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+#include <alloca.h>
+
+/* This testcase checks that `alloca` calls ensure the `__hwasan_generate_tag`
+   function is called to initialize the base tag.  `alloca` calls are treated
+   differently to standard variables.  The prologue/epilogue sequence is
+   generated mainly based on normal stack-allocated objects.
+
+   We want to ensure that though the `alloca` call is not poisoned/unpoisoned
+   by the prologue and epilogue, the use of them in a given function still
+   triggers the prologue sequence to emit a call to __hwasan_generate_tag (and
+   hence that any call to __hwasan_generate_tag is emitted in the unconditional
+   part of the function code).  */
+
+int choice = 0;
+int record = 1;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+__attribute__ ((noinline))
+unsigned char
+__hwasan_generate_tag ()
+{
+  record = 0;
+  return 3;
+}
+#ifdef __cplusplus
+}
+#endif
+
+__attribute__ ((noinline))
+int
+generate_tag_was_missed (void)
+{
+  return record;
+}
+
+__attribute__((noinline, noclone)) int
+foo (char *a)
+{
+  int i, j = 0;
+  asm volatile ("" : "+r" (a) : : "memory");
+  for (i = 0; i < 12; i++)
+    j += a[i];
+  return j;
+}
+
+int
+main ()
+{
+  if (choice)
+  {
+        char *x = (char *)alloca(100);
+        foo(x);
+  }
+  else
+  {
+        char *y = (char *)alloca(20);
+        foo(y);
+  }
+  return generate_tag_was_missed ();
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/alloca-gets-different-tag.c b/gcc/testsuite/c-c++-common/hwasan/alloca-gets-different-tag.c
new file mode 100644 (file)
index 0000000..e83734f
--- /dev/null
@@ -0,0 +1,65 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+/* Alloca is given a different tag to other variables.
+   vararray should behave in the same way.  */
+
+#define alloca __builtin_alloca
+#define assert(x) if (!(x)) __builtin_abort ()
+
+struct two_values {
+    int left;
+    int right;
+};
+
+/* Require default hwasan tag ABI.
+   Know we're using AArch64 since that's the only architecture we run hwasan
+   tests on.  */
+char tag_of (void * x) { return ((unsigned long long)x) >> 56; }
+
+int __attribute__ ((noinline))
+alloca_different_tag (int num)
+{
+  struct two_values tmp_object = {
+      .left = 100,
+      .right = num,
+  };
+  int *big_array = (int *)alloca (num * sizeof (int));
+  int other_array[100];
+  
+  char first_tag = tag_of (&tmp_object);
+  char second_tag = tag_of (big_array);
+  char other_tag = tag_of (other_array);
+  assert (first_tag != second_tag);
+  assert (second_tag != other_tag);
+  assert (first_tag != other_tag);
+  return 0;
+}
+
+int __attribute__ ((noinline))
+vararray_different_tag (int num)
+{
+  struct two_values tmp_object = {
+      .left = 100,
+      .right = num,
+  };
+  int big_array[num];
+  int other_array[100];
+  
+  char first_tag = tag_of (&tmp_object);
+  char second_tag = tag_of (big_array);
+  char other_tag = tag_of (other_array);
+  assert (first_tag != second_tag);
+  assert (second_tag != other_tag);
+  assert (first_tag != other_tag);
+  return 0;
+}
+
+int __attribute__ ((noinline))
+main ()
+{
+  alloca_different_tag (10);
+  vararray_different_tag (8);
+  return 0;
+}
+
diff --git a/gcc/testsuite/c-c++-common/hwasan/alloca-outside-caught.c b/gcc/testsuite/c-c++-common/hwasan/alloca-outside-caught.c
new file mode 100644 (file)
index 0000000..60d7a9a
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+#define alloca __builtin_alloca
+
+int __attribute__ ((noinline))
+check_alloca (int num)
+{
+  volatile int *allocd_array = (int*)alloca (num * sizeof(int));
+  int other_array[10];
+  return allocd_array[12];
+}
+
+int __attribute__ ((noinline))
+main ()
+{
+  check_alloca (3);
+  return 1;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/arguments-1.c b/gcc/testsuite/c-c++-common/hwasan/arguments-1.c
new file mode 100644 (file)
index 0000000..435dad3
--- /dev/null
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-hwaddress" } */
+/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with '-fsanitize=kernel-hwaddress'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/arguments-2.c b/gcc/testsuite/c-c++-common/hwasan/arguments-2.c
new file mode 100644 (file)
index 0000000..fafde99
--- /dev/null
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-address" } */
+/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with '-fsanitize=kernel-address'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/arguments-3.c b/gcc/testsuite/c-c++-common/hwasan/arguments-3.c
new file mode 100644 (file)
index 0000000..6e907b4
--- /dev/null
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=thread" } */
+/* { dg-error ".*'-fsanitize=thread' is incompatible with '-fsanitize=hwaddress'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/arguments.c b/gcc/testsuite/c-c++-common/hwasan/arguments.c
new file mode 100644 (file)
index 0000000..7c11314
--- /dev/null
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=address" } */
+/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with '-fsanitize=address'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/asan-pr63316.c b/gcc/testsuite/c-c++-common/hwasan/asan-pr63316.c
new file mode 100644 (file)
index 0000000..dd3b3db
--- /dev/null
@@ -0,0 +1,24 @@
+/* PR sanitizer/63316 */
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern void *malloc (__SIZE_TYPE__);
+extern void free (void *);
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+  int *p = (int *) malloc (sizeof (int));
+  *p = 3;
+  asm volatile ("" : : "r" (p) : "memory");
+  free (p);
+  return 0;
+}
+
diff --git a/gcc/testsuite/c-c++-common/hwasan/asan-pr70541.c b/gcc/testsuite/c-c++-common/hwasan/asan-pr70541.c
new file mode 100644 (file)
index 0000000..ba2ed49
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
+/* { dg-shouldfail "hwasan" } */
+
+#include <stdio.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern void *malloc (__SIZE_TYPE__);
+extern void free (void *);
+#ifdef __cplusplus
+}
+#endif
+
+struct Simple {
+  int value;
+};
+
+int f(struct Simple simple) {
+  return simple.value;
+}
+
+int main() {
+  struct Simple *psimple = (struct Simple *) malloc(sizeof(struct Simple));
+  psimple->value = 42;
+  free(psimple);
+  printf("%d\n", f(*psimple));
+  return 0;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "freed by thread T0 here:.*" } */
+/* { dg-output "previously allocated here:" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/asan-pr78106.c b/gcc/testsuite/c-c++-common/hwasan/asan-pr78106.c
new file mode 100644 (file)
index 0000000..3f53ad1
--- /dev/null
@@ -0,0 +1,31 @@
+/* PR sanitizer/78106 */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=hwaddress -fdump-tree-sanopt-details -ffat-lto-objects" } */
+
+int *variable;
+
+void __attribute__((used)) release()
+{
+  __builtin_free (variable);
+}
+
+int main2(int argc)
+{
+  *variable = 2;
+
+  if (argc <= 5)
+    asm volatile ("call release");
+
+  *variable = 2;
+  __builtin_abort ();
+
+  return 0;
+}
+
+int main(int argc, char **argv)
+{
+  variable = (int *)__builtin_malloc (sizeof(int));
+  return main2(argc);
+}
+
+/* { dg-final { scan-tree-dump-not "Optimizing out(\n|\r\n|\r)  HWASAN_CHECK \\(7, variable.*" "sanopt" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/asan-pr79944.c b/gcc/testsuite/c-c++-common/hwasan/asan-pr79944.c
new file mode 100644 (file)
index 0000000..7d54f54
--- /dev/null
@@ -0,0 +1,19 @@
+/* PR sanitizer/79944 */
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+struct S { int i; char p[1024]; };
+
+int
+main ()
+{
+  struct S *p = (struct S *) __builtin_malloc (__builtin_offsetof (struct S, p) + 64);
+  p->i = 5;
+  asm volatile ("" : "+r" (p) : : "memory");
+  __atomic_fetch_add ((int *) p, 5, __ATOMIC_RELAXED);
+  asm volatile ("" : "+r" (p) : : "memory");
+  if (p->i != 10)
+    __builtin_abort ();
+  __builtin_free (p);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/asan-rlimit-mmap-test-1.c b/gcc/testsuite/c-c++-common/hwasan/asan-rlimit-mmap-test-1.c
new file mode 100644 (file)
index 0000000..5426b8a
--- /dev/null
@@ -0,0 +1,24 @@
+/* Check that we properly report mmap failure. */
+
+/* { dg-do run { target setrlimit } } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
+/* { dg-require-effective-target hw } */
+/* { dg-shouldfail "hwasan" } */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static volatile void *x;
+
+int main(int argc, char **argv) {
+  struct rlimit mmap_resource_limit = { 0, 0 };
+  if (setrlimit(RLIMIT_AS, &mmap_resource_limit)) return 1;
+  x = malloc(10000000);
+  return 0;
+}
+
+/* { dg-output "ERROR: Failed to mmap" } */
+
diff --git a/gcc/testsuite/c-c++-common/hwasan/bitfield-1.c b/gcc/testsuite/c-c++-common/hwasan/bitfield-1.c
new file mode 100644 (file)
index 0000000..0c3479e
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+struct bitmapped_struct {
+    unsigned one : 1;
+    unsigned two : 1;
+    unsigned three : 1;
+    unsigned four : 1;
+    unsigned five : 1;
+    unsigned six : 1;
+    unsigned seven : 1;
+    unsigned eight : 1;
+};
+
+/* Check that hwasan allows valid bitfield accesses. */
+int __attribute__ ((noinline))
+handle_unaligned_access (struct bitmapped_struct *foo)
+{
+  if (foo->three)
+    return foo->four;
+
+  foo->five = 1;
+  return 1;
+}
+
+int main()
+{
+  struct bitmapped_struct myvar = {0};
+  handle_unaligned_access (&myvar);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/bitfield-2.c b/gcc/testsuite/c-c++-common/hwasan/bitfield-2.c
new file mode 100644 (file)
index 0000000..0b3f3aa
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+/* Ensure that hwasan instruments bitfield accesses.  */
+struct A
+{
+  /* Ensure the offset from the start of this struct to the bitfield we access
+     is large enough to be in a different tag.  */
+  char base[16];
+  int : 4;
+  long x : 7;
+};
+
+int __attribute__ ((noinline, noclone))
+f (void *p) {
+  return ((struct A *)p)->x;
+}
+
+int
+main ()
+{
+  char a = 0;
+  return f (&a);
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 2 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c b/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c
new file mode 100644 (file)
index 0000000..a7a6d91
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-asan" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+/* Only skip the -flto tests without the -flto-partition=none.
+   With -flto-partition=none we still get a asan1 dump file, without that
+   parameter we only get the lto dump files (which means scan-tree-dump-times
+   doesn't work.  */
+/* { dg-skip-if "" { *-*-* }  { "-flto" } { "-flto-partition=none" } } */
+
+typedef __SIZE_TYPE__ size_t;
+/* Functions to observe that HWASAN instruments memory builtins in the expected
+   manner.  */
+void * __attribute__((noinline))
+memset_builtin (void *dest, int value, size_t len)
+{
+  return __builtin_memset (dest, value, len);
+}
+
+/* HWASAN avoids strlen because it doesn't know the size of the memory access
+   until *after* the function call.  */
+size_t __attribute__ ((noinline))
+strlen_builtin (char *element)
+{
+  return __builtin_strlen (element);
+}
+
+/* First test ensures that the HWASAN_CHECK was emitted before the
+   memset.  Second test ensures there was only HWASAN_CHECK (which demonstrates
+   that strlen was not instrumented).  */
+/* { dg-final { scan-tree-dump-times "HWASAN_CHECK.*memset" 1 "asan1" } } */
+/* { dg-final { scan-tree-dump-times "HWASAN_CHECK" 1 "asan1" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/check-interface.c b/gcc/testsuite/c-c++-common/hwasan/check-interface.c
new file mode 100644 (file)
index 0000000..90f52ca
--- /dev/null
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/*
+   Test taken from LLVM
+    compiler-rt/test/hwasan/TestCases/check-interface.cpp
+ */
+// Utilizes all flavors of __hwasan_load/store interface functions to verify
+// that the instrumentation and the interface provided by HWASan do match.
+// In case of a discrepancy, this test fails to link.
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT32_TYPE__ uint32_t;
+typedef __UINT64_TYPE__ uint64_t;
+
+#define F(T) void f_##T(T *a, T *b) { *a = *b; }
+
+F(uint8_t)
+F(uint16_t)
+F(uint32_t)
+F(uint64_t)
+
+typedef unsigned V32 __attribute__((__vector_size__(32)));
+F(V32)
+
+int main() {}
diff --git a/gcc/testsuite/c-c++-common/hwasan/halt_on_error-1.c b/gcc/testsuite/c-c++-common/hwasan/halt_on_error-1.c
new file mode 100644 (file)
index 0000000..90ca856
--- /dev/null
@@ -0,0 +1,24 @@
+/* Test recovery mode.  */
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-options "-fsanitize-recover=hwaddress" } */
+/* { dg-set-target-env-var HWASAN_OPTIONS "halt_on_error=false" } */
+/* { dg-shouldfail "hwasan" } */
+
+volatile int sixteen = 16;
+
+int main() {
+  char x[16];
+  __builtin_memset(x, 0, sixteen + 1);
+  asm volatile ("" : : : "memory");
+  volatile int res = x[sixteen];
+  x[sixteen] = res + 3;
+  res = x[sixteen];
+  return 0;
+}
+
+/* { dg-output "WRITE of size 17 at 0x\[0-9a-f\]+.*" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+.*" } */
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+.*" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+.*" } */
+
diff --git a/gcc/testsuite/c-c++-common/hwasan/handles-poly_int-marked-vars.c b/gcc/testsuite/c-c++-common/hwasan/handles-poly_int-marked-vars.c
new file mode 100644 (file)
index 0000000..685b780
--- /dev/null
@@ -0,0 +1,37 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-additional-options "-march=armv8.6-a+sve -fsanitize-address-use-after-scope" } */
+
+#include <arm_sve.h>
+
+__attribute__((noinline, noclone)) int
+foo (char *a)
+{
+  int i, j = 0;
+  asm volatile ("" : "+r" (a) : : "memory");
+  for (i = 0; i < 12; i++)
+    j += a[i];
+  return j;
+}
+
+int
+main ()
+{
+  int i, j = 0;
+  for (i = 0; i < 4; i++)
+    {
+      char a[12];
+      __SVInt8_t freq;
+      /* Just do something with that `freq` variable so that the compiler
+        doesn't optimise its use away.  */
+      if (__builtin_bcmp (&freq, a, 10))
+       j += 1;
+      __builtin_memset (a, 0, sizeof (a));
+      j += foo (a);
+    }
+  return j;
+}
+
+/* Just ensure this compiles without giving an ICE.
+   This is the equivalent of PR 97696 but for HWASAN.  HWASAN can handle
+   poly_int sized variables, and this testcase ensures that we don't ICE when
+   given them.  */
diff --git a/gcc/testsuite/c-c++-common/hwasan/heap-overflow.c b/gcc/testsuite/c-c++-common/hwasan/heap-overflow.c
new file mode 100644 (file)
index 0000000..1374668
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free -fno-builtin-memset" } */
+/* { dg-shouldfail "hwasan" } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void *memset (void *, int, __SIZE_TYPE__);
+void *malloc (__SIZE_TYPE__);
+void free (void *);
+#ifdef __cplusplus
+}
+#endif
+
+volatile int ten = 10;
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10);
+  memset(x, 0, 10);
+  int res = x[ten];  /* BOOOM */
+  free(x);
+  return res;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "located 0 bytes to the right of 10-byte region.*" } */
+/* { dg-output "allocated here:.*" } */
+/* { dg-output "#1 0x\[0-9a-f\]+ +in _*main \[^\n\r]*heap-overflow.c:18" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/hwasan-poison-optimisation.c b/gcc/testsuite/c-c++-common/hwasan/hwasan-poison-optimisation.c
new file mode 100644 (file)
index 0000000..2d6bab4
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+/* { dg-additional-options "-fdump-tree-asan1 -save-temps" } */
+
+/* Here to check that the ASAN_POISON stuff works just fine.
+   This mechanism isn't very often used, but I should at least go through the
+   code-path once in my testfile.  */
+int
+main ()
+{
+  int *ptr = 0;
+
+  {
+    int a;
+    ptr = &a;
+    *ptr = 12345;
+  }
+
+  return *ptr;
+}
+
+/* { dg-final { scan-tree-dump-times "ASAN_POISON" 1 "asan1" }  } */
+/* { dg-final { scan-assembler-times "bl\\s*__hwasan_tag_mismatch4" 1 } } */
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-access-parent.c b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-access-parent.c
new file mode 100644 (file)
index 0000000..828909d
--- /dev/null
@@ -0,0 +1,51 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "-lpthread" } */
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int printf (char const *, ...);
+#ifdef __cplusplus
+}
+#endif
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __UINT64_TYPE__ uint64_t;
+
+/* Test that tags are checked across different threads.
+   i.e. if this thread tries to access a different threads memory with the
+   incorrect tag, then this thread fails.  */
+void *
+failing_thread_function (void *argument)
+{
+    void * other = (void *)((uint64_t)argument & 0xffffffffffffffULL);
+    int *num = (int*)argument;
+    printf ("(should succeed): first number = %d\n", num[0]);
+    printf ("(now should fail):\n");
+
+    int *othernum = (int*)other;
+    printf (" second number = %d\n", othernum[0]);
+    return (void *)1;
+}
+
+int
+main (int argc, char **argv)
+{
+    int argument[100] = {0};
+    argument[1] = 10;
+    pthread_t thread_index;
+    pthread_create (&thread_index, NULL, failing_thread_function, (void*)argument);
+
+    void *retval;
+    pthread_join (thread_index, &retval);
+
+    return (uintptr_t)retval;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: 00/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T1.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-basic-failure.c b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-basic-failure.c
new file mode 100644 (file)
index 0000000..6a07521
--- /dev/null
@@ -0,0 +1,48 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "-lpthread" } */
+
+/* Ensure the failure mode for hwasan under pthreads looks sane.
+   (Looks sane means that the same error message is printed out rather than an
+   opaque message due to mishandling).  */
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int printf (char const *, ...);
+#ifdef __cplusplus
+}
+#endif
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __UINT64_TYPE__ uint64_t;
+
+void *
+failing_from_stack (void * argument)
+{
+    int internal_array[16] = {0};
+    printf ("(now should fail):");
+    printf (" problem number is %d\n", internal_array[17]);
+    return (void *)1;
+}
+
+int
+main (int argc, char **argv)
+{
+    int argument[100] = {0};
+    argument[1] = 10;
+    pthread_t thread_index;
+    pthread_create (&thread_index, NULL, failing_from_stack, (void*)argument);
+
+    void *retval;
+    pthread_join (thread_index, &retval);
+
+    return (uintptr_t)retval;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T1.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T1.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c
new file mode 100644 (file)
index 0000000..09c72a5
--- /dev/null
@@ -0,0 +1,56 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "-lpthread" } */
+
+/* This checks the interceptor ABI pthread hooks.
+   The stack of the thread that is finishing must be cleared of shadow tags
+   when that thread exits.  */
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int printf (char const *, ...);
+#ifdef __cplusplus
+}
+#endif
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __UINT64_TYPE__ uint64_t;
+
+__attribute__ ((noinline))
+void * Ident (void * argument)
+{
+       return argument;
+}
+
+void *
+pthread_stack_is_cleared (void *argument)
+{
+   (void)argument;
+   int internal_array[16] = {0};
+   return Ident((void*)internal_array);
+}
+
+int
+main (int argc, char **argv)
+{
+    int argument[100] = {0};
+    argument[1] = 10;
+    pthread_t thread_index;
+    pthread_create (&thread_index, NULL, pthread_stack_is_cleared, (void*)argument);
+
+    void *retval;
+    pthread_join (thread_index, &retval);
+
+    printf ("(should fail): ");
+    printf ("value left in stack is: %d\n", ((int *)retval)[0]);
+
+    return (uintptr_t)retval;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "HWAddressSanitizer can not describe address in more detail\..*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-success.c b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-success.c
new file mode 100644 (file)
index 0000000..b0281f7
--- /dev/null
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-additional-options "-lpthread" } */
+
+/* Just ensure that a basic threaded program works while running with hwasan.
+   */
+
+#include <pthread.h>
+
+extern int printf (const char *, ...);
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __UINT64_TYPE__ uint64_t;
+
+void *
+successful_thread_function (void * argument)
+{
+    int *deref = (int *)argument;
+    if (deref[0] == 100)
+      deref[1] = 10;
+    return (void *)0;
+}
+
+int
+main (int argc, char **argv)
+{
+    int argument[100] = {0};
+    argument[1] = 10;
+    pthread_t thread_index;
+    pthread_create (&thread_index, NULL, successful_thread_function, (void*)argument);
+
+    void *retval;
+    pthread_join (thread_index, &retval);
+
+    return (uintptr_t)retval;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/kernel-defaults.c b/gcc/testsuite/c-c++-common/hwasan/kernel-defaults.c
new file mode 100644 (file)
index 0000000..abfe735
--- /dev/null
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-sanitize=hwaddress -fsanitize=kernel-hwaddress" } */
+
+
+/* Defaults to check for kernel-hwaddress.
+   1) No stack tagging => no calls to __hwasan_tag_memory.
+   2) No block scope tagging (same again).
+   3) Use sanitize-recover by default (everything ends in noabort). */
+int __attribute__ ((noinline))
+accessing_pointers (int *left, int *right)
+{
+  int x = right[2];
+  left[3] = right[1];
+  return right[1] + left[2];
+}
+
+int __attribute__ ((noinline))
+using_stack (int num)
+{
+  int big_array[10];
+  int other_array[20];
+  accessing_pointers(other_array, big_array);
+  return big_array[num];
+}
+
+#ifndef ARG
+#define ARG 0
+#endif
+int __attribute__ ((noinline))
+main ()
+{
+  using_stack (ARG);
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "__hwasan_tag_memory" } } */
+/* { dg-final { scan-assembler-not "__hwasan_(load|store)\\d(?!_noabort)" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-0.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-0.c
new file mode 100644 (file)
index 0000000..5b0071a
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+/* Handling large aligned variables.
+   Large aligned variables take a different code-path through expand_stack_vars
+   in cfgexpand.c.  This testcase is just to exercise that code-path.
+
+   The alternate code-path produces a second base-pointer through some
+   instructions emitted in the prologue.
+   
+   Test cases are:
+   0) Valid access works without complaint.
+   1) Invalid access is caught.  */
+int __attribute__ ((noinline))
+handle_large_alignment (int num)
+{
+  int other_array[10];
+  int big_array[100] __attribute__ ((aligned (32)));
+  return big_array[num] + other_array[num];
+}
+
+#ifndef ARG
+#define ARG 1
+#endif
+
+int global;
+
+int __attribute__ ((noinline))
+main ()
+{
+  global += handle_large_alignment (ARG);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-1.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-1.c
new file mode 100644 (file)
index 0000000..1aa1303
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+#define ARG 12
+#include "large-aligned-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-0.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-0.c
new file mode 100644 (file)
index 0000000..11f422f
--- /dev/null
@@ -0,0 +1,75 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* Don't really need this option since there are no vararray/alloca objects in
+   the interesting function, however it never hurts to make doubly sure and
+   make it explicit that we're checking the alternate approach to deallocation.
+   */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+/* Handling large aligned variables.
+   Large aligned variables take a different code-path through expand_stack_vars
+   in cfgexpand.c.  This testcase is just to exercise that code-path.
+
+   The alternate code-path produces a second base-pointer through some
+   instructions emitted in the prologue.
+
+   This eventually follows a different code path for untagging when not tagging
+   allocas. The untagging needs to work at the top of the frame, and this
+   should account for this different base when large aligned variables are
+   around.  */
+__attribute__ ((noinline))
+void * Ident (void * argument)
+{
+  return argument;
+}
+
+#ifndef ALIGNMENT
+#define ALIGNMENT
+#endif
+void __attribute__ ((noinline))
+large_alignment_untagging (int num, int *retval, int **big, int **other)
+{
+  int other_array[100] ALIGNMENT;
+  int big_array[100] __attribute__ ((aligned (32)));
+  *retval = big_array[num] + other_array[num];
+  *big = (int*)Ident(big_array);
+  *other = (int*)Ident(other_array);
+}
+
+#ifndef ARG
+#define ARG 0
+#endif
+
+int global;
+
+int __attribute__ ((noinline))
+main ()
+{
+  int retval;
+  int *big, *other;
+  large_alignment_untagging (0, &retval, &big, &other);
+  /* Want to test that both ends of both variables are untagged.  */
+  switch (ARG) {
+    case 0:
+      global += big[0];
+      break;
+    case 1:
+      global += big[99];
+      break;
+    case 2:
+      global += other[0];
+      break;
+    case 3:
+      global += other[99];
+      break;
+  }
+  return 0;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-1.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-1.c
new file mode 100644 (file)
index 0000000..b2fc522
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+#define ARG 1
+#include "large-aligned-untagging-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-2.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-2.c
new file mode 100644 (file)
index 0000000..ebc4648
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+#define ARG 2
+#include "large-aligned-untagging-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-3.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-3.c
new file mode 100644 (file)
index 0000000..d3a226a
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+#define ARG 3
+#include "large-aligned-untagging-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-4.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-4.c
new file mode 100644 (file)
index 0000000..cdd122b
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+#define ARG 0
+#define ALIGNMENT __attribute__ ((aligned (32)))
+#include "large-aligned-untagging-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-5.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-5.c
new file mode 100644 (file)
index 0000000..7c4cb5c
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+#define ARG 1
+#define ALIGNMENT __attribute__ ((aligned (32)))
+#include "large-aligned-untagging-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-6.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-6.c
new file mode 100644 (file)
index 0000000..f429ed2
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+#define ARG 2
+#define ALIGNMENT __attribute__ ((aligned (32)))
+#include "large-aligned-untagging-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-7.c b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-7.c
new file mode 100644 (file)
index 0000000..56f16eb
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
+
+#define ARG 3
+#define ALIGNMENT __attribute__ ((aligned (32)))
+#include "large-aligned-untagging-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* NOTE: This assumes the current tagging mechanism (one at a time from the
+   base and large aligned variables being handled first).  */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/macro-definition.c b/gcc/testsuite/c-c++-common/hwasan/macro-definition.c
new file mode 100644 (file)
index 0000000..5f654f5
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+extern void testfunc(int);
+int foo()
+{
+#ifndef __SANITIZE_HWADDRESS__
+  testfunc(1);
+#endif
+  return 1;
+}
+
+/* { dg-final { scan-assembler-not "testfunc" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/no-sanitize-attribute.c b/gcc/testsuite/c-c++-common/hwasan/no-sanitize-attribute.c
new file mode 100644 (file)
index 0000000..c0a254d
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+
+__attribute__((no_sanitize("hwaddress"))) int
+f (int *p, int *q)
+{
+  *p = 42;
+  return *q;
+}
+
+/* Only have one instance of __hwasan, it is __hwasan_init (the module
+ * constructor) there is no instrumentation in the function.  */
+/* { dg-final { scan-assembler-times "__hwasan" 1 } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/param-instrument-mem-intrinsics.c b/gcc/testsuite/c-c++-common/hwasan/param-instrument-mem-intrinsics.c
new file mode 100644 (file)
index 0000000..f1e6dc8
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+/* { dg-additional-options "--param hwasan-instrument-mem-intrinsics=0" } */
+
+#include "builtin-special-handling.c"
+
+/* With this flag there should be no checking of builtins.
+   The above file only has builtins, and hence there should be no checking
+   after compilation.  */
+/* { dg-final { scan-assembler-not "__hwasan_(load|store)" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/param-instrument-reads-and-writes.c b/gcc/testsuite/c-c++-common/hwasan/param-instrument-reads-and-writes.c
new file mode 100644 (file)
index 0000000..1d565a2
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-instrument-writes=0" } */
+
+#include "param-instrument-reads.c"
+
+/* { dg-final { scan-assembler "__hwasan_load" } } */
+/* { dg-final { scan-assembler-not "__hwasan_store" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/param-instrument-reads.c b/gcc/testsuite/c-c++-common/hwasan/param-instrument-reads.c
new file mode 100644 (file)
index 0000000..9b8049a
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-instrument-reads=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+/* Particular code doesn't really matter, the requirement is that it has both
+   loads and stores in it.  */
+__attribute__ ((noinline))
+int reader (int *array, size_t num)
+{
+  return array[num];
+}
+
+int __attribute__ ((noinline))
+writer (int *array, size_t num, int value)
+{
+  array[num] = value;
+  return num + value;
+}
+
+/* { dg-final { scan-assembler-not "__hwasan_load" } } */
+/* { dg-final { scan-assembler "__hwasan_store" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/param-instrument-writes.c b/gcc/testsuite/c-c++-common/hwasan/param-instrument-writes.c
new file mode 100644 (file)
index 0000000..0f04fad
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-instrument-reads=0 --param hwasan-instrument-writes=0" } */
+
+#include "param-instrument-reads.c"
+
+/* { dg-final { scan-assembler-not "__hwasan_load" } } */
+/* { dg-final { scan-assembler-not "__hwasan_store" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/random-frame-tag.c b/gcc/testsuite/c-c++-common/hwasan/random-frame-tag.c
new file mode 100644 (file)
index 0000000..8e55b29
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-random-frame-tag=1" } */
+
+#include "stack-tagging-basic-0.c"
+
+/* Random frame tag => call to __hwasan_generate_tag.  */
+/* { dg-final { scan-assembler "__hwasan_generate_tag" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/sanity-check-pure-c.c b/gcc/testsuite/c-c++-common/hwasan/sanity-check-pure-c.c
new file mode 100644 (file)
index 0000000..a42921b
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
+/* { dg-shouldfail "asan" } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void *malloc (__SIZE_TYPE__);
+void free (void *);
+#ifdef __cplusplus
+}
+#endif
+
+int main() {
+  char *x = (char*)malloc(10);
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "located 5 bytes inside of 10-byte region.*" } */
+/* { dg-output "freed by thread T0 here:.*" } */
+/* { dg-output "previously allocated here:" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-0.c b/gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-0.c
new file mode 100644 (file)
index 0000000..019c4ea
--- /dev/null
@@ -0,0 +1,54 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+#include <setjmp.h>
+#include <stdio.h>
+
+/*
+   Testing longjmp/setjmp should test.
+
+   0) Nothing special happens with the jmp_buf.
+   1) Accesses to scopes jmp'd over are caught.
+ */
+int __attribute__ ((noinline))
+uses_longjmp (int **other_array, int num, jmp_buf env)
+{
+  int internal_array[100] = {0};
+  *other_array = &internal_array[0];
+  if (num % 2)
+    longjmp (env, num);
+  else
+    return num % 8;
+}
+
+int __attribute__ ((noinline))
+uses_setjmp (int num)
+{ 
+  int big_array[100];
+  int *other_array = NULL;
+  sigjmp_buf cur_env;
+  int temp = 0;
+  if ((temp = sigsetjmp (cur_env, 1)) != 0)
+    { 
+      if (other_array != NULL)
+        printf ("Value pointed to in other_array[0]: %d\n",
+                other_array[0]);
+  
+      printf ("Longjmp returned %d.\n", temp);
+      return 10;
+    }
+  else
+    {
+      return uses_longjmp (&other_array, num, cur_env);
+    } 
+} 
+
+#ifndef ARG
+#define ARG 0
+#endif
+int __attribute__ ((noinline))
+main ()
+{
+  uses_setjmp (ARG);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-1.c b/gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-1.c
new file mode 100644 (file)
index 0000000..6a4fcee
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+/*
+   Testing longjmp/setjmp should test.
+
+   0) Nothing special happens with the jmp_buf.
+   1) Accesses to scopes jmp'd over are caught.
+ */
+
+#define ARG 1
+#include "setjmp-longjmp-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-0.c b/gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-0.c
new file mode 100644 (file)
index 0000000..1141141
--- /dev/null
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+/* Basic tests for stack tagging.
+
+   0) Valid accesses work.
+   1) Accesses outside of a variable crash.
+*/
+int __attribute__ ((noinline))
+accessing_pointers (int *left, int *right)
+{
+  int x = right[2];
+  left[3] = right[1];
+  return right[1] + left[2];
+}
+
+int __attribute__ ((noinline))
+using_stack (int num)
+{
+  int big_array[10];
+  int other_array[20];
+  accessing_pointers(other_array, big_array);
+  return big_array[num];
+}
+
+#ifndef ARG
+#define ARG 0
+#endif
+
+int global;
+
+int __attribute__ ((noinline))
+main ()
+{
+  global += using_stack (ARG);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-1.c b/gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-1.c
new file mode 100644 (file)
index 0000000..90d5837
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+/* Basic tests for stack tagging.
+
+   0) Accesses outside of a variable crash.
+   1) Valid accesses work.
+*/
+
+#define ARG 17
+#include "stack-tagging-basic-0.c"
+#undef ARG
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/stack-tagging-disable.c b/gcc/testsuite/c-c++-common/hwasan/stack-tagging-disable.c
new file mode 100644 (file)
index 0000000..9bcae16
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-instrument-stack=0" } */
+
+
+/* No stack tagging => no calls to __hwasan_tag_memory.  */
+int __attribute__ ((noinline))
+accessing_pointers (int *left, int *right)
+{
+  int x = right[2];
+  left[3] = right[1];
+  return right[1] + left[2];
+}
+
+int __attribute__ ((noinline))
+using_stack (int num)
+{
+  int big_array[10];
+  int other_array[20];
+  accessing_pointers(other_array, big_array);
+  return big_array[num];
+}
+
+#ifndef ARG
+#define ARG 0
+#endif
+int __attribute__ ((noinline))
+main ()
+{
+  using_stack (ARG);
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "__hwasan_tag_memory" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-0.c b/gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-0.c
new file mode 100644 (file)
index 0000000..8846515
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0 -save-temps" } */
+/* Only run this test without optimisation.  When running with optimisation we
+   use the unprotected-allocas-1.c file that also checks there are no memory
+   tagging calls (since when optimised the only variable on the stack should be
+   the vararray/alloca).  */
+/* { dg-skip-if "" { *-*-* } { "-O1" "-O2" "-O3" } { "" } } */
+
+#define alloca __builtin_alloca
+#define assert(x) if (!(x)) __builtin_abort ()
+
+char tag_of (void * x) { return ((unsigned long long)x) >> 56; }
+
+int __attribute__ ((noinline))
+using_alloca (int num)
+{
+  int retval = 0;
+  int *big_array = (int*)alloca (num * sizeof (int));
+  char alloca_tag = tag_of (big_array);
+  assert (alloca_tag == 0);
+  for (int i = 0; i < num; ++i) {
+      retval += big_array[i];
+  }
+  return retval;
+}
+
+int __attribute__ ((noinline))
+using_vararray (int num)
+{
+  int retval = 0;
+  int big_array[num];
+  char vararray_tag = tag_of (big_array);
+  assert (vararray_tag == 0);
+  for (int i = 0; i < num; ++i) {
+      retval += big_array[i];
+  }
+  return retval;
+}
+
+int main()
+{
+  using_alloca (16);
+  using_vararray (12);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-1.c b/gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-1.c
new file mode 100644 (file)
index 0000000..752edc1
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-additional-options "--param hwasan-instrument-allocas=0 -save-temps" } */
+/* Only test there's no tagging done when not at -O0.  Without optimisation
+   the compiler creates a bunch of other variables on the stack other than the
+   vararray/alloca object.
+   We also avoid checking when using -flto, since with LTO the compiler can
+   recognise the vararray is only used with one size and that size is known at
+   compile time -- when the compiler recognises that it instead creates a
+   static array, which gets tagged as is expected but not as the test expects.
+   */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-flto" } { "" } } */
+
+#include "unprotected-allocas-0.c"
+
+/* { dg-final { scan-assembler-not "__hwasan_tag_memory" } } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/use-after-free.c b/gcc/testsuite/c-c++-common/hwasan/use-after-free.c
new file mode 100644 (file)
index 0000000..41a3569
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
+/* { dg-shouldfail "hwasan" } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void *malloc (__SIZE_TYPE__);
+void free (void *);
+#ifdef __cplusplus
+}
+#endif
+
+int main() {
+  char *x = (char*)malloc(10);
+  free(x);
+  return x[5];
+}
+
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "is located 5 bytes inside of 10-byte region.*" } */
+/* { dg-output "freed by thread T0 here:.*" } */
+/* { dg-output "#1\[^\n\r]*main\[^\n\r]*use-after-free.c:17.*" } */
+/* { dg-output "previously allocated here:.*" } */
+/* { dg-output "#1\[^\n\r]*main\[^\n\r]*use-after-free.c:16" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/vararray-outside-caught.c b/gcc/testsuite/c-c++-common/hwasan/vararray-outside-caught.c
new file mode 100644 (file)
index 0000000..35a344d
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+int __attribute__ ((noinline))
+check_vararray (int num)
+{
+  int var_array[num];
+  int other_array[10];
+  return var_array[12];
+}
+
+int __attribute__ ((noinline))
+main ()
+{
+  return check_vararray (3);
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/c-c++-common/hwasan/vararray-stack-restore-correct.c b/gcc/testsuite/c-c++-common/hwasan/vararray-stack-restore-correct.c
new file mode 100644 (file)
index 0000000..f4e1f57
--- /dev/null
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+#include <stdio.h>
+
+/* Testing that a function with outgoing arguments correctly decrements the
+   stack pointer when a vararray goes out of scope.  */
+
+const char *
+other (int argc, int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l)
+{
+  const char ** other;
+    {
+      const char * test_array[argc];
+      test_array[0] = "test string";
+      test_array[argc - 1] = "hello";
+      /* To prevent optimisation.  */
+      printf("While the value stored in our test_array is: %s\n",
+            test_array[argc - 1]);
+      other = test_array;
+    }
+  /* With the below function call (the one with many arguments), some of the
+     arguments have to be put on the stack, which means we have to reserve some
+     space on the stack for these arguments and that the VLA is stored at a
+     position that is not the stack pointer. */
+  printf("Hello there!\nOur numbers today are: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
+        a, b, c, d, e, f, g, h, i, j, k, l);
+  /* This should fail due to a bad read access.  */
+  return other[0];
+}
+
+int
+main ()
+{
+  int a, b, c, d, e, f, g, h, i, j, k, l;
+  const char * retval = other (1, a, b, c, d, e, f, g, h, i, j, k, l);
+  /* Numbers don't matter here, just want to ensure the program is reading them
+     so we know they won't be optimised out.  */
+  if (retval)
+    return 1;
+  return 10;
+}
diff --git a/gcc/testsuite/c-c++-common/hwasan/very-large-objects.c b/gcc/testsuite/c-c++-common/hwasan/very-large-objects.c
new file mode 100644 (file)
index 0000000..5526535
--- /dev/null
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+
+/* Ensure the sanitizer can handle very large offsets (i.e. that the hooks
+   handle offsets too large for the relevant instructions).
+   Just want to make sure this compiles without an ICE.  */
+#ifndef ASIZE
+# define ASIZE 0x10000000000UL
+#endif
+
+typedef __UINT64_TYPE__ uint64_t;
+
+#if __LONG_MAX__ < 8 * ASIZE
+# undef ASIZE
+# define ASIZE 4096
+#endif
+
+extern void abort (void);
+
+int __attribute__((noinline))
+foo (const char *s)
+{
+  if (!s)
+    return 1;
+  if (s[0] != 'a')
+    abort ();
+  s += ASIZE - 1;
+  if (s[0] != 'b')
+    abort ();
+  return 0;
+}
+
+int (*fn) (const char *) = foo;
+
+int __attribute__((noinline))
+bar (void)
+{
+  char s[ASIZE];
+  s[0] = 'a';
+  s[ASIZE - 1] = 'b';
+  foo (s);
+  foo (s);
+  return 0;
+}
+
+int __attribute__((noinline))
+baz (long i)
+{
+  if (i)
+    return fn (0);
+  else
+    {
+      char s[ASIZE];
+      s[0] = 'a';
+      s[ASIZE - 1] = 'b';
+      foo (s);
+      foo (s);
+      return fn (0);
+    }
+}
+
+int __attribute__((noinline))
+very_large_offset (int *p)
+{
+  char init_array[(uint64_t)0xfefefef];
+  char other_array[(uint64_t)0xfefefef];
+  return (int)init_array[p[1]] + (int)other_array[p[0]];
+}
+
index f325a7472289595d6b489f121dcd91d795a85c8b..55db0c0b865ac93d0525f0cc0775f4080fc3d4b1 100644 (file)
@@ -3,4 +3,4 @@
 
 int i;
 
-/* { dg-error ".-fsanitize=thread. is incompatible with .-fsanitize=address|kernel-address." "" { target *-*-* } 0 } */
+/* { dg-error ".-fsanitize=thread. is incompatible with .-fsanitize=address." "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/g++.dg/hwasan/hwasan.exp b/gcc/testsuite/g++.dg/hwasan/hwasan.exp
new file mode 100644 (file)
index 0000000..559cf06
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (C) 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Load support procs.
+load_lib g++-dg.exp
+load_lib hwasan-dg.exp
+
+# Initialize `dg'.
+dg-init
+hwasan_init
+
+# Main loop.
+if [check_effective_target_fsanitize_hwaddress] {
+  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/hwasan/*.c]] "" ""
+}
+
+# All done.
+hwasan_finish
+dg-finish
diff --git a/gcc/testsuite/g++.dg/hwasan/rvo-handled.C b/gcc/testsuite/g++.dg/hwasan/rvo-handled.C
new file mode 100644 (file)
index 0000000..0e30ff0
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+#define assert(x) if (!(x)) __builtin_abort ()
+typedef __UINTPTR_TYPE__ uintptr_t;
+void *untagged (void *ptr)
+{
+  /* Untag by removing the top byte.  */
+  return (void*)((uintptr_t)ptr & 0xffffffffffffff);
+}
+
+struct big_struct {
+    int left;
+    int right;
+    void *ptr;
+    int big_array[100];
+};
+
+/*
+   Tests for RVO (basically, checking -fsanitize=hwaddress has not broken RVO
+   in any way).
+
+   0) The value is accessible in both functions without a hwasan complaint.
+   1) RVO does happen.
+ */
+
+struct big_struct __attribute__ ((noinline))
+return_on_stack()
+{
+  struct big_struct x;
+  x.left = 100;
+  x.right = 20;
+  x.big_array[10] = 30;
+  x.ptr = untagged(&x);
+  return x;
+}
+
+int main()
+{
+  struct big_struct x;
+  x = return_on_stack();
+  /* Check that RVO happens by checking the address that the callee saw.  */
+  assert (x.ptr == untagged(&x));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/hwasan/hwasan.exp b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp
new file mode 100644 (file)
index 0000000..5c040ae
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (C) 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+load_lib hwasan-dg.exp
+
+# Initialize `dg'.
+dg-init
+hwasan_init
+
+# Main loop.
+if [check_effective_target_fsanitize_hwaddress] {
+  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/hwasan/*.c]] "" ""
+}
+
+# All done.
+hwasan_finish
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/hwasan/nested-functions-0.c b/gcc/testsuite/gcc.dg/hwasan/nested-functions-0.c
new file mode 100644 (file)
index 0000000..0afcc10
--- /dev/null
@@ -0,0 +1,53 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+
+/*
+   Tests of nested funtions are:
+    0) Accessing closed over variables works.
+    1) Accesses outside of variables is caught.
+    2) Accessing variable out of scope is caught.
+
+    Here we test that accessing closed over variables works.
+ */
+
+/* We need a second layer of indirection so that GCC doesn't notice we're
+   returning the address of a local variable and put 0 in it's place.  */
+__attribute__((noinline))
+int *Ident(void *x) {
+  return x;
+}
+
+int __attribute__ ((noinline))
+intermediate (void (*f) (int, char),
+             char num)
+{
+  if (num == 1)
+    /* NOTE: We need to overrun by an amount greater than the "extra data" in a
+       nonlocal goto structure.  The entire structure is allocated on the stack
+       with a single tag, which means hwasan can't tell if a closed-over buffer
+       was overrun by an amount small enough that the access was still to some
+       data in that nonlocal goto structure.  */
+    f (100, 100);
+  else
+    f (3, 100);
+  /* Just return something ... */
+  return num % 3;
+}
+
+int* __attribute__ ((noinline))
+nested_function (char num)
+{
+  int big_array[16];
+  int other_array[16];
+  void store (int index, char value)
+    { big_array[index] = value; }
+  return Ident(&other_array[intermediate (store, num)]);
+}
+
+#ifndef MAIN
+int main ()
+{
+  nested_function (0);
+  return 0;
+}
+#endif
diff --git a/gcc/testsuite/gcc.dg/hwasan/nested-functions-1.c b/gcc/testsuite/gcc.dg/hwasan/nested-functions-1.c
new file mode 100644 (file)
index 0000000..0161281
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+/*
+   Tests of nested funtions are:
+    0) Accessing closed over variables works.
+    1) Accesses outside of variables is caught.
+    2) Accessing variable out of scope is caught.
+
+    Here we test option 1.
+ */
+
+#define MAIN 0
+#include "nested-functions-0.c"
+#undef MAIN
+
+int main ()
+{
+  nested_function (1);
+  return 0;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "WRITE of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
diff --git a/gcc/testsuite/gcc.dg/hwasan/nested-functions-2.c b/gcc/testsuite/gcc.dg/hwasan/nested-functions-2.c
new file mode 100644 (file)
index 0000000..b1a033f
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-require-effective-target hwaddress_exec } */
+/* { dg-shouldfail "hwasan" } */
+
+/*
+   Tests of nested funtions are:
+    0) Accessing closed over variables works.
+    1) Accesses outside of variables is caught.
+    2) Accessing variable out of scope is caught.
+
+    Here we test option 2.
+ */
+
+#define MAIN 0
+#include "nested-functions-0.c"
+#undef MAIN
+
+int main ()
+{
+  int *retval = nested_function (2);
+  *retval = 100;
+  return 0;
+}
+
+/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
+/* { dg-output "WRITE of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
+/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
+/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */
index ce745dfdf8d34a03a7c8008d2e7faf7a223658ec..8f96751bfacf9364bfd18ea4ded3d545b3caa774 100644 (file)
@@ -16,6 +16,9 @@
 
 # Return 1 if compilation with -fsanitize=address is error-free for trivial
 # code, 0 otherwise.
+#
+# NOTE: This should only be used between calls to asan_init and asan_finish.
+# It is therefore defined here rather than in target-supports.exp.
 
 proc check_effective_target_fsanitize_address {} {
     if ![check_no_compiler_messages fsanitize_address executable {
@@ -58,33 +61,33 @@ proc asan_include_flags {} {
 # (originally from g++.exp)
 #
 
-proc asan_link_flags { paths } {
+proc asan_link_flags_1 { paths lib } {
     global srcdir
     global ld_library_path
     global shlib_ext
-    global asan_saved_library_path
+    global ${lib}_saved_library_path
 
     set gccpath ${paths}
     set flags ""
 
     set shlib_ext [get_shlib_extension]
-    set asan_saved_library_path $ld_library_path
+    set ${lib}_saved_library_path $ld_library_path
 
     if { $gccpath != "" } {
-      if { [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.a"]
-          || [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.${shlib_ext}"] } {
+      if { [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.a"]
+          || [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.${shlib_ext}"] } {
          append flags " -B${gccpath}/libsanitizer/ "
-         append flags " -B${gccpath}/libsanitizer/asan/ "
-         append flags " -L${gccpath}/libsanitizer/asan/.libs "
-         append ld_library_path ":${gccpath}/libsanitizer/asan/.libs"
+         append flags " -B${gccpath}/libsanitizer/${lib}/ "
+         append flags " -L${gccpath}/libsanitizer/${lib}/.libs "
+         append ld_library_path ":${gccpath}/libsanitizer/${lib}/.libs"
       }
     } else {
       global tool_root_dir
 
-      set libasan [lookfor_file ${tool_root_dir} libasan]
-      if { $libasan != "" } {
-         append flags "-L${libasan} "
-         append ld_library_path ":${libasan}"
+      set libdir [lookfor_file ${tool_root_dir} lib${lib}]
+      if { $libdir != "" } {
+         append flags "-L${libdir} "
+         append ld_library_path ":${libdir}"
       }
     }
 
@@ -93,6 +96,10 @@ proc asan_link_flags { paths } {
     return "$flags"
 }
 
+proc asan_link_flags { paths } {
+    return [asan_link_flags_1 $paths asan]
+}
+
 #
 # asan_init -- called at the start of each subdir of tests
 #
diff --git a/gcc/testsuite/lib/hwasan-dg.exp b/gcc/testsuite/lib/hwasan-dg.exp
new file mode 100644 (file)
index 0000000..892f2ba
--- /dev/null
@@ -0,0 +1,150 @@
+# Copyright (C) 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib asan-dg.exp
+
+# Return 1 if target can compile a binary for hardware address
+# sanitization, 0 otherwise.
+#
+# NOTE: This should only be used between calls to hwasan_init and
+# hwasan_finish.  It is therefore defined here rather than in
+# target-supports.exp.
+
+proc check_effective_target_fsanitize_hwaddress {} {
+    if ![check_no_compiler_messages fsanitize_hwaddress executable {
+       int main (void) { return 0; }
+    }] {
+       return 0;
+    }
+    return 1;
+}
+
+# Return 1 if target can compile and run a binary for hardware address
+# sanitization, 0 otherwise.
+#
+# NOTE: This should only be used between calls to hwasan_init and
+# hwasan_finish.  It is therefore defined here rather than in
+# target-supports.exp.
+
+proc check_effective_target_hwaddress_exec {} {
+    if ![check_runtime hwaddress_exec {
+       int main (void) { return 0; }
+    }] {
+       return 0;
+    }
+    return 1;
+}
+
+proc hwasan_include_flags {} {
+    global srcdir
+    global TESTING_IN_BUILD_TREE
+
+    set flags ""
+
+    if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } {
+      return "${flags}"
+    }
+
+    set flags "-I$srcdir/../../libsanitizer/include"
+
+    return "$flags"
+}
+
+#
+# hwasan_link_flags -- compute library path and flags to find libhwasan.
+# (implementation in asan-dg.exp)
+#
+
+proc hwasan_link_flags { paths } {
+    return [asan_link_flags_1 $paths hwasan]
+}
+
+#
+# hwasan_init -- called at the start of each subdir of tests
+#
+
+proc hwasan_init { args } {
+    global TEST_ALWAYS_FLAGS
+    global ALWAYS_CXXFLAGS
+    global TOOL_OPTIONS
+    global hwasan_saved_TEST_ALWAYS_FLAGS
+    global hwasan_saved_ALWAYS_CXXFLAGS
+
+    setenv HWASAN_OPTIONS "random_tags=0"
+
+    set link_flags ""
+    if ![is_remote host] {
+       if [info exists TOOL_OPTIONS] {
+           set link_flags "[hwasan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
+       } else {
+           set link_flags "[hwasan_link_flags [get_multilibs]]"
+       }
+    }
+
+    set include_flags "[hwasan_include_flags]"
+
+    if [info exists TEST_ALWAYS_FLAGS] {
+       set hwasan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
+    }
+    if [info exists ALWAYS_CXXFLAGS] {
+       set hwasan_saved_ALWAYS_CXXFLAGS $ALWAYS_CXXFLAGS
+       set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
+       set ALWAYS_CXXFLAGS [concat "{additional_flags=-fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags}" $ALWAYS_CXXFLAGS]
+    } else {
+       if [info exists TEST_ALWAYS_FLAGS] {
+           set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags $TEST_ALWAYS_FLAGS"
+       } else {
+           set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags"
+       }
+    }
+}
+
+#
+# hwasan_finish -- called at the start of each subdir of tests
+#
+
+proc hwasan_finish { args } {
+    global TEST_ALWAYS_FLAGS
+    global hwasan_saved_TEST_ALWAYS_FLAGS
+    global hwasan_saved_ALWAYS_CXXFLAGS
+    global hwasan_saved_library_path
+    global ld_library_path
+
+    unsetenv HWASAN_OPTIONS
+
+    if [info exists hwasan_saved_ALWAYS_CXXFLAGS ] {
+       set ALWAYS_CXXFLAGS $hwasan_saved_ALWAYS_CXXFLAGS
+    } else {
+       if [info exists hwasan_saved_TEST_ALWAYS_FLAGS] {
+           set TEST_ALWAYS_FLAGS $hwasan_saved_TEST_ALWAYS_FLAGS
+       } else {
+           unset TEST_ALWAYS_FLAGS
+       }
+    }
+    if [info exists hwasan_saved_library_path] {
+       set ld_library_path $hwasan_saved_library_path
+       set_ld_library_path_env_vars
+    }
+    clear_effective_target_cache
+}
+
+# Utility for running gtest hwasan emulation under dejagnu, invoked via dg-final.
+# Call pass if variable has the desired value, otherwise fail.
+#
+# Argument 0 handles expected failures and the like
+proc hwasan-gtest { args } {
+    asan-gtest {*}$args
+}