[PATCH 7/X] [libsanitizer] Add tests

Matthew Malcomson Matthew.Malcomson@arm.com
Mon Dec 16 11:47:00 GMT 2019


I just remembered that the run tests all fail on cross builds.
This patch includes the effective target check to determine whether a hwasan
binary can be run on a given target.

We then add that target requirement to all tests which need to run.



Adding hwasan tests.

Only interesting thing here is that we have to make sure the tagging mechanism
is deterministic to avoid flaky tests.

gcc/testsuite/ChangeLog:

2019-12-16  Matthew Malcomson  <matthew.malcomson@arm.com>

	* c-c++-common/hwasan/aligned-alloc.c: New test.
	* c-c++-common/hwasan/alloca-array-accessible.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.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/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/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/macro-definition.c: New test.
	* c-c++-common/hwasan/no-sanitize-attribute.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/param-memintrin.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 file.
	* g++.dg/hwasan/rvo-handled.C: New test.
	* gcc.dg/hwasan/hwasan.exp: New file.
	* 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.



###############     Attachment also inlined for ease of reply    ###############


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
index 0000000000000000000000000000000000000000..d38b1f3f62d97dc3f5c3882137c370700fd4f9a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/aligned-alloc.c
@@ -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
index 0000000000000000000000000000000000000000..5e4c168f77efac5c9335768fb5b76fb3752783e9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/alloca-array-accessible.c
@@ -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-gets-different-tag.c b/gcc/testsuite/c-c++-common/hwasan/alloca-gets-different-tag.c
new file mode 100644
index 0000000000000000000000000000000000000000..e83734f4b79c2d35a49039797cba6b2506febbe5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/alloca-gets-different-tag.c
@@ -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
index 0000000000000000000000000000000000000000..60d7a9a874f90e2c5c461a33f144dcb431dea838
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/alloca-outside-caught.c
@@ -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
index 0000000000000000000000000000000000000000..435dad3cf159f565e56406467c41d97506f45d8f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/arguments-1.c
@@ -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
index 0000000000000000000000000000000000000000..90012e4cc49057de8b352fea488ba52636bfef32
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/arguments-2.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-address" } */
+/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with both '-fsanitize=address' and '-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
index 0000000000000000000000000000000000000000..02fdb1ee26e37e59191ba8d4e0f769f2360f7a11
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/arguments-3.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=thread" } */
+/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with '-fsanitize=thread'.*" "" { 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
index 0000000000000000000000000000000000000000..2dedbf1d737c559c7046e5749b5e5b8459a9cbf9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/arguments.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=address" } */
+/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with both '-fsanitize=address' and '-fsanitize=kernel-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
index 0000000000000000000000000000000000000000..dd3b3dbf22505f12063f088821fecd4be44817d0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/asan-pr63316.c
@@ -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
index 0000000000000000000000000000000000000000..ba2ed496e6ee81b13270ce05831ff01eca98edde
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/asan-pr70541.c
@@ -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
index 0000000000000000000000000000000000000000..3f53ad17693cc4fbb246bc0d3f6a1d02fc3222d0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/asan-pr78106.c
@@ -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
index 0000000000000000000000000000000000000000..7d54f54701bac6b8337d62ec9f6fbbb69f921a37
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/asan-pr79944.c
@@ -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
index 0000000000000000000000000000000000000000..5426b8ab430df1813be4e1cbf0930cfa4d817c48
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/asan-rlimit-mmap-test-1.c
@@ -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
index 0000000000000000000000000000000000000000..0c3479eacc477fa4d4aaa15846bb73a40a5fbb48
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/bitfield-1.c
@@ -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
index 0000000000000000000000000000000000000000..0b3f3aaaf2d899eb3f946e8f230601e16d491d4c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/bitfield-2.c
@@ -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
index 0000000000000000000000000000000000000000..69f112d2d4ffb1c0b9af7df83cdbd1e789c8d12c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-hwasan" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+/* Only skip the -flto tests without the -flto-partition=none.
+   With -flto-partition=none we still get a hwasan1 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 "hwasan1" } } */
+/* { dg-final { scan-tree-dump-times "HWASAN_CHECK" 1 "hwasan1" } } */
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
index 0000000000000000000000000000000000000000..90f52cac884dd67b1dab18d4037fe64dfc19eefc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/check-interface.c
@@ -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
index 0000000000000000000000000000000000000000..90ca856874dfbdd8266981a26503f1e5b88cf039
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/halt_on_error-1.c
@@ -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/heap-overflow.c b/gcc/testsuite/c-c++-common/hwasan/heap-overflow.c
new file mode 100644
index 0000000000000000000000000000000000000000..48ebb56bdf407bb147dd1e404897ce79662b2d05
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/heap-overflow.c
@@ -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:17" } */
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
index 0000000000000000000000000000000000000000..8726102cb1c84931ecfe99ea4f255ef1a70ccd8a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/hwasan-poison-optimisation.c
@@ -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-hwasan1 -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 "hwasan1" }  } */
+/* { 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
index 0000000000000000000000000000000000000000..828909d3b3bc6ad98fdb243cb6a06e78bcff4280
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-access-parent.c
@@ -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
index 0000000000000000000000000000000000000000..6a07521e1155de5bdbc95fad00d1305b2f33548e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-basic-failure.c
@@ -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
index 0000000000000000000000000000000000000000..09c72a56f0f50a8c301d89217aa8c7df70087e6c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c
@@ -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
index 0000000000000000000000000000000000000000..b0281f7b389f141f17c08fdb76db8848d0e7c429
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-success.c
@@ -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
index 0000000000000000000000000000000000000000..abfe735e6e1fab712ae8f0bd1517a14a4d5eb178
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/kernel-defaults.c
@@ -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
index 0000000000000000000000000000000000000000..5b0071af2beccc36246ddf9406c087dde4b52f80
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/large-aligned-0.c
@@ -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
index 0000000000000000000000000000000000000000..1aa130323960225c2201067d29f83231f1cec5d7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/large-aligned-1.c
@@ -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
index 0000000000000000000000000000000000000000..99a4e162169d54c40b101641623017695a93f55f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-0.c
@@ -0,0 +1,60 @@
+/* { 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;
+}
+
+int* __attribute__ ((noinline))
+large_alignment_untagging (int num)
+{
+  int other_array[100];
+  int big_array[100] __attribute__ ((aligned (32)));
+  if (num % 1)
+    return (int*)Ident(big_array);
+  else
+    return (int*)Ident(other_array);
+}
+
+#ifndef ARG
+#define ARG 1
+#endif
+
+int global;
+
+int __attribute__ ((noinline))
+main ()
+{
+  int *array = large_alignment_untagging (ARG);
+  /* Want to test that both ends of the function are untagged.
+     That means both the start of the large aligned variable and the end of the
+     other variable.  */
+  global += array[ARG ? 99 : 0];
+  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
index 0000000000000000000000000000000000000000..1c0cf11c4d59ed77692b3c1ac97327c6cc4e558f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/large-aligned-untagging-1.c
@@ -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 0
+#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
index 0000000000000000000000000000000000000000..5f654f557821f2dbe060e9976fbca7e5770f274c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/macro-definition.c
@@ -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
index 0000000000000000000000000000000000000000..d5ff4aec06c8bc6c80fe512061ccc8908e321153
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/no-sanitize-attribute.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+
+__attribute__((no_sanitize_hwaddress)) int
+f1 (int *p, int *q)
+{
+  *p = 42;
+  return *q;
+}
+
+__attribute__((no_sanitize("hwaddress"))) int
+f2 (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 functions.  */
+/* { dg-final { scan-assembler-times "__hwasan" 1 } } */
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
index 0000000000000000000000000000000000000000..1d565a2f5d959507fc7ba2418637489f7e14e6f0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/param-instrument-reads-and-writes.c
@@ -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
index 0000000000000000000000000000000000000000..9b8049a3cb94b166a2b27bbc97f8c26ac7efc6ac
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/param-instrument-reads.c
@@ -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
index 0000000000000000000000000000000000000000..0f04fad6496253f31d09e49b49b77decbefe0e60
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/param-instrument-writes.c
@@ -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/param-memintrin.c b/gcc/testsuite/c-c++-common/hwasan/param-memintrin.c
new file mode 100644
index 0000000000000000000000000000000000000000..e52d6fe7df43256fe4acfe2ecc71c5cdeb36bef4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/param-memintrin.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+/* { dg-additional-options "--param hwasan-memintrin=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/random-frame-tag.c b/gcc/testsuite/c-c++-common/hwasan/random-frame-tag.c
new file mode 100644
index 0000000000000000000000000000000000000000..8e55b298470a49bf5563f26013569ee03487933c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/random-frame-tag.c
@@ -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
index 0000000000000000000000000000000000000000..a42921bb44cf835696e00731849b33b4ef069b72
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/sanity-check-pure-c.c
@@ -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
index 0000000000000000000000000000000000000000..019c4ea3f7467be61da52272b37a3fd5d1924df7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-0.c
@@ -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
index 0000000000000000000000000000000000000000..6a4fceeb37acb156b0b92556453f6fc1bf49b876
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/setjmp-longjmp-1.c
@@ -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
index 0000000000000000000000000000000000000000..114114165d97ef5b5c6c2fa83352cc7f071d3695
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-0.c
@@ -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
index 0000000000000000000000000000000000000000..90d5837254f8dddadfc2235fe5e7191c45e7887b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/stack-tagging-basic-1.c
@@ -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
index 0000000000000000000000000000000000000000..c48048988b7ca97507f5305cc2c30af1e8421bee
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/stack-tagging-disable.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-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
index 0000000000000000000000000000000000000000..88465155c6d0a72bfef1fdd31c59adaf4db549ce
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-0.c
@@ -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
index 0000000000000000000000000000000000000000..752edc1d3ea366af771936d7680902bad7c1878c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/unprotected-allocas-1.c
@@ -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
index 0000000000000000000000000000000000000000..22dea56c644c25d660c26d6753d0ec4c5b0797fc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/use-after-free.c
@@ -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:16.*" } */
+/* { dg-output "previously allocated here:.*" } */
+/* { dg-output "#1\[^\n\r]*main\[^\n\r]*use-after-free.c:15" } */
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
index 0000000000000000000000000000000000000000..35a344def424e41dc9e810fdf0e804294efa75df
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/vararray-outside-caught.c
@@ -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
index 0000000000000000000000000000000000000000..f4e1f57bdd2e92c9adf1158e60096ab5a72f38e8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/vararray-stack-restore-correct.c
@@ -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
index 0000000000000000000000000000000000000000..55265353369540872e8fba4da99d9be92a7ad99b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/very-large-objects.c
@@ -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]];
+}
+
diff --git a/gcc/testsuite/g++.dg/hwasan/hwasan.exp b/gcc/testsuite/g++.dg/hwasan/hwasan.exp
new file mode 100644
index 0000000000000000000000000000000000000000..559cf066f18cc82601661a751bf702303c66c888
--- /dev/null
+++ b/gcc/testsuite/g++.dg/hwasan/hwasan.exp
@@ -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
index 0000000000000000000000000000000000000000..0e30ff054fc65610996b7cdf3e5dcd6dbeeffe6c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/hwasan/rvo-handled.C
@@ -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
index 0000000000000000000000000000000000000000..5c040aec24a222e4024a548e055c52cee4afe8f8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp
@@ -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
index 0000000000000000000000000000000000000000..0afcc100508cd2a5467698e901e32fa2292a32c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/nested-functions-0.c
@@ -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
index 0000000000000000000000000000000000000000..016128101e23c6405d943f4a2a4729f7c48ff95a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/nested-functions-1.c
@@ -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
index 0000000000000000000000000000000000000000..b1a033fdb365cf53882fc1d8294b32bbad16ea8a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/nested-functions-2.c
@@ -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\]*.*" } */
diff --git a/gcc/testsuite/lib/hwasan-dg.exp b/gcc/testsuite/lib/hwasan-dg.exp
new file mode 100644
index 0000000000000000000000000000000000000000..78942fbe0f2c4958ea8cd060f4d3f83400f50895
--- /dev/null
+++ b/gcc/testsuite/lib/hwasan-dg.exp
@@ -0,0 +1,364 @@
+# Copyright (C) 2012-2019 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/>.
+
+# Return 1 if compilation with -fsanitize=hwaddress is error-free for trivial
+# code, 0 otherwise.
+
+proc check_effective_target_fsanitize_hwaddress {} {
+    if ![check_no_compiler_messages fsanitize_hwaddress executable {
+	int main (void) { return 0; }
+    }] {
+	return 0;
+    }
+    return 1;
+}
+
+proc check_effective_target_hwaddress_exec {} {
+    if ![check_runtime hwaddress_exec {
+	int main (void) { return 0; }
+    }] {
+	return 0;
+    }
+    return 1;
+
+    # hwasan doesn't work if there's a ulimit on virtual memory.
+    if ![is_remote target] {
+	if [catch {exec sh -c "ulimit -v"} ulimit_v] {
+	    # failed to get ulimit
+	} elseif [regexp {^[0-9]+$} $ulimit_v] {
+	    # ulimit -v gave a numeric limit
+	    warning "skipping hwasan tests due to ulimit -v"
+	    return 0;
+	}
+    }
+}
+
+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.
+# (originally from g++.exp)
+#
+
+proc hwasan_link_flags { paths } {
+    global srcdir
+    global ld_library_path
+    global shlib_ext
+    global hwasan_saved_library_path
+
+    set gccpath ${paths}
+    set flags ""
+
+    set shlib_ext [get_shlib_extension]
+    set hwasan_saved_library_path $ld_library_path
+
+    if { $gccpath != "" } {
+      if { [file exists "${gccpath}/libsanitizer/hwasan/.libs/libhwasan.a"]
+	   || [file exists "${gccpath}/libsanitizer/hwasan/.libs/libhwasan.${shlib_ext}"] } {
+	  append flags " -B${gccpath}/libsanitizer/ "
+	  append flags " -B${gccpath}/libsanitizer/hwasan/ "
+	  append flags " -L${gccpath}/libsanitizer/hwasan/.libs "
+	  append ld_library_path ":${gccpath}/libsanitizer/hwasan/.libs"
+      }
+    } else {
+      global tool_root_dir
+
+      set libhwasan [lookfor_file ${tool_root_dir} libhwasan]
+      if { $libhwasan != "" } {
+	  append flags "-L${libhwasan} "
+	  append ld_library_path ":${libhwasan}"
+      }
+    }
+
+    set_ld_library_path_env_vars
+
+    return "$flags"
+}
+
+#
+# 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
+	}
+    }
+    set ld_library_path $hwasan_saved_library_path
+    set_ld_library_path_env_vars
+    clear_effective_target_cache
+}
+
+# Symbolize lines like
+#   #2 0xdeadbeef (/some/path/libsanitizer.so.0.0.0+0xbeef)
+# in $output using addr2line to
+#   #2 0xdeadbeef in foobar file:123
+proc hwasan_symbolize { output } {
+    set addresses [regexp -inline -all -line "^ *#\[0-9\]+ 0x\[0-9a-f\]+ \[(\](\[^)\]+)\[+\](0x\[0-9a-f\]+)\[)\]$" "$output"]
+    if { [llength $addresses] > 0 } {
+	set addr2line_name [find_binutils_prog addr2line]
+	set idx 1
+	while { $idx < [llength $addresses] } {
+	    set key [regsub -all "\[\]\[\]" [lindex $addresses $idx] "\\\\&"]
+	    set val [lindex $addresses [expr $idx + 1]]
+	    lappend arr($key) $val
+	    set idx [expr $idx + 3]
+	}
+	foreach key [array names arr] {
+	    set args "-f -e $key $arr($key)"
+	    set status [remote_exec host "$addr2line_name" "$args"]
+	    if { [lindex $status 0] > 0 } continue
+	    regsub -all "\r\n" [lindex $status 1] "\n" addr2line_output
+	    regsub -all "\[\n\r\]BFD: \[^\n\r\]*" $addr2line_output "" addr2line_output
+	    regsub -all "^BFD: \[^\n\r\]*\[\n\r\]" $addr2line_output "" addr2line_output
+	    set addr2line_output [regexp -inline -all -line "^\[^\n\r]*" $addr2line_output]
+	    set idx 0
+	    foreach val $arr($key) {
+		if { [expr $idx + 1] < [llength $addr2line_output] } {
+		    set fnname [lindex $addr2line_output $idx]
+		    set fileline [lindex $addr2line_output [expr $idx + 1]]
+		    if { "$fnname" != "??" } {
+			set newkey "$key+$val"
+			set repl($newkey) "$fnname $fileline"
+		    }
+		    set idx [expr $idx + 2]
+		}
+	    }
+	}
+	set idx 0
+	set new_output ""
+	while {[regexp -start $idx -indices " #\[0-9\]+ 0x\[0-9a-f\]+ \[(\](\[^)\]+\[+\]0x\[0-9a-f\]+)\[)\]" "$output" -> addr] > 0} {
+	    set low [lindex $addr 0]
+	    set high [lindex $addr 1]
+	    set val [string range "$output" $low $high]
+	    append new_output [string range "$output" $idx [expr $low - 2]]
+	    if [info exists repl($val)] {
+		append new_output "in $repl($val)"
+	    } else {
+		append new_output "($val)"
+	    }
+	    set idx [expr $high + 2]
+	}
+	append new_output [string range "$output" $idx [string length "$output"]]
+	return "$new_output"
+    }
+    return "$output"
+}
+
+# Return a list of gtest tests, printed in the form
+# DEJAGNU_GTEST_TEST AddressSanitizer_SimpleDeathTest
+# DEJAGNU_GTEST_TEST AddressSanitizer_VariousMallocsTest
+proc hwasan_get_gtest_test_list { output } {
+    set idx 0
+    set ret ""
+    while {[regexp -start $idx -indices "DEJAGNU_GTEST_TEST (\[^\n\r\]*)(\r\n|\n|\r)" "$output" -> testname] > 0} {
+	set low [lindex $testname 0]
+	set high [lindex $testname 1]
+	set val [string range "$output" $low $high]
+	lappend ret $val
+	set idx [expr $high + 1]
+    }
+    return $ret
+}
+
+# Return a list of gtest EXPECT_DEATH tests, printed in the form
+# DEJAGNU_GTEST_EXPECT_DEATH1 statement DEJAGNU_GTEST_EXPECT_DEATH1 regexp DEJAGNU_GTEST_EXPECT_DEATH1
+# DEJAGNU_GTEST_EXPECT_DEATH2 other statement DEJAGNU_GTEST_EXPECT_DEATH2 other regexp DEJAGNU_GTEST_EXPECT_DEATH2
+proc hwasan_get_gtest_expect_death_list { output } {
+    set idx 0
+    set ret ""
+    while {[regexp -start $idx -indices "DEJAGNU_GTEST_EXPECT_DEATH(\[0-9\]*)" "$output" -> id ] > 0} {
+	set low [lindex $id 0]
+	set high [lindex $id 1]
+	set val_id [string range "$output" $low $high]
+	if {[regexp -start $low -indices "$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id\[\n\r\]" "$output" whole statement regexpr ] == 0} { break }
+	set low [lindex $statement 0]
+	set high [lindex $statement 1]
+	set val_statement [string range "$output" $low $high]
+	set low [lindex $regexpr 0]
+	set high [lindex $regexpr 1]
+	set val_regexpr [string range "$output" $low $high]
+	lappend ret [list "$val_id" "$val_statement" "$val_regexpr"]
+	set idx [lindex $whole 1]
+    }
+    return $ret
+}
+
+# Replace ${tool}_load with a wrapper so that we can symbolize the output.
+if { [info procs ${tool}_load] != [list] \
+      && [info procs saved_hwasan_${tool}_load] == [list] } {
+    rename ${tool}_load saved_hwasan_${tool}_load
+
+    proc ${tool}_load { program args } {
+	global tool
+	global hwasan_last_gtest_test_list
+	global hwasan_last_gtest_expect_death_list
+	set result [eval [list saved_hwasan_${tool}_load $program] $args]
+	set output [lindex $result 1]
+	set symbolized_output [hwasan_symbolize "$output"]
+	set hwasan_last_gtest_test_list [hwasan_get_gtest_test_list "$output"]
+	set hwasan_last_gtest_expect_death_list [hwasan_get_gtest_expect_death_list "$output"]
+	set result [list [lindex $result 0] $symbolized_output]
+	return $result
+    }
+}
+
+# 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 } {
+    global tool
+    global hwasan_last_gtest_test_list
+    global hwasan_last_gtest_expect_death_list
+
+    if { ![info exists hwasan_last_gtest_test_list] } { return }
+    if { [llength $hwasan_last_gtest_test_list] == 0 } { return }
+    if { ![isnative] || [is_remote target] } { return }
+
+    set gtest_test_list $hwasan_last_gtest_test_list
+    unset hwasan_last_gtest_test_list
+
+    if { [llength $args] >= 1 } {
+	switch [dg-process-target [lindex $args 0]] {
+	    "S" { }
+	    "N" { return }
+	    "F" { setup_xfail "*-*-*" }
+	    "P" { }
+	}
+    }
+
+    # This assumes that we are three frames down from dg-test, and that
+    # it still stores the filename of the testcase in a local variable "name".
+    # A cleaner solution would require a new DejaGnu release.
+    upvar 2 name testcase
+    upvar 2 prog prog
+
+    set output_file "[file rootname [file tail $prog]].exe"
+
+    foreach gtest $gtest_test_list {
+	set testname "$testcase $gtest"
+	set status -1
+
+	setenv DEJAGNU_GTEST_ARG "$gtest"
+	set result [${tool}_load ./$output_file $gtest]
+	unsetenv DEJAGNU_GTEST_ARG
+	set status [lindex $result 0]
+	set output [lindex $result 1]
+	if { "$status" == "pass" } {
+	    pass "$testname execution test"
+	    if { [info exists hwasan_last_gtest_expect_death_list] } {
+		set gtest_expect_death_list $hwasan_last_gtest_expect_death_list
+		foreach gtest_death $gtest_expect_death_list {
+		    set id [lindex $gtest_death 0]
+		    set testname "$testcase $gtest [lindex $gtest_death 1]"
+		    set regexpr [lindex $gtest_death 2]
+		    set status -1
+
+		    setenv DEJAGNU_GTEST_ARG "$gtest:$id"
+		    set result [${tool}_load ./$output_file "$gtest:$id"]
+		    unsetenv DEJAGNU_GTEST_ARG
+		    set status [lindex $result 0]
+		    set output [lindex $result 1]
+		    if { "$status" == "fail" } {
+			pass "$testname execution test"
+			if { ![regexp $regexpr ${output}] } {
+			    fail "$testname output pattern test"
+			    send_log "Output should match: $regexpr\n"
+			} else {
+			    pass "$testname output pattern test"
+			}
+		    } elseif { "$status" == "pass" } {
+			fail "$testname execution test"
+		    } else {
+			$status "$testname execution test"
+		    }
+		}
+	    }
+	} else {
+	    $status "$testname execution test"
+	}
+	unset hwasan_last_gtest_expect_death_list
+    }
+
+    return
+}

-------------- next part --------------
A non-text attachment was scrubbed...
Name: updated-tests.patch.gz
Type: application/gzip
Size: 15266 bytes
Desc: updated-tests.patch.gz
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20191216/c2a0292b/attachment.gz>


More information about the Gcc-patches mailing list