This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 16/X] [libsanitizer] Add tests


Adding hwasan tests.

Frankly, these could be tidied up a little.
I will be tidying them up while getting feedback on the hwasan introduction.


gcc/testsuite/ChangeLog:

2019-11-05  Matthew Malcomson  <matthew.malcomson@arm.com>

	* c-c++-common/hwasan/arguments.c: New test.
	* c-c++-common/hwasan/halt_on_error-1.c: New test.
	* g++.dg/hwasan/rvo-handled.c: New test.
	* g++.dg/hwasan/try-catch-0.cpp: New test.
	* g++.dg/hwasan/try-catch-1.cpp: New test.
	* gcc.dg/hwasan/aligned-alloc.c: New test.
	* gcc.dg/hwasan/alloca-array-accessible.c: New test.
	* gcc.dg/hwasan/alloca-gets-different-tag.c: New test.
	* gcc.dg/hwasan/alloca-outside-caught.c: New test.
	* gcc.dg/hwasan/bitfield-1.c: New test.
	* gcc.dg/hwasan/bitfield-2.c: New test.
	* gcc.dg/hwasan/builtin-special-handling.c: New test.
	* gcc.dg/hwasan/check-interface.c: New test.
	* gcc.dg/hwasan/hwasan-poison-optimisation.c: New test.
	* gcc.dg/hwasan/hwasan-thread-access-parent.c: New test.
	* gcc.dg/hwasan/hwasan-thread-basic-failure.c: New test.
	* gcc.dg/hwasan/hwasan-thread-clears-stack.c: New test.
	* gcc.dg/hwasan/hwasan-thread-success.c: New test.
	* gcc.dg/hwasan/hwasan.exp: New file.
	* gcc.dg/hwasan/kernel-defaults.c: New test.
	* gcc.dg/hwasan/large-aligned-0.c: New test.
	* gcc.dg/hwasan/large-aligned-1.c: New test.
	* gcc.dg/hwasan/macro-definition.c: 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.
	* gcc.dg/hwasan/no-sanitize-attribute.c: New test.
	* gcc.dg/hwasan/random-frame-tag.c: New test.
	* gcc.dg/hwasan/setjmp-longjmp-0.c: New test.
	* gcc.dg/hwasan/setjmp-longjmp-1.c: New test.
	* gcc.dg/hwasan/stack-tagging-basic-0.c: New test.
	* gcc.dg/hwasan/stack-tagging-basic-1.c: New test.
	* gcc.dg/hwasan/stack-tagging-disable.c: New test.
	* gcc.dg/hwasan/vararray-outside-caught.c: New test.
	* gcc.dg/hwasan/very-large-objects.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/arguments.c b/gcc/testsuite/c-c++-common/hwasan/arguments.c
new file mode 100644
index 0000000000000000000000000000000000000000..2d563eb8541694d501b021babd9452fd7fd502a3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/arguments.c
@@ -0,0 +1,7 @@
+/*
+   TODO
+   Somehow test the conflict of arguments
+   -fsanitize=hwaddress -fsanitize=kernel-address
+   -fsanitize=hwaddress -fsanitize=address
+   -fsanitize=hwaddress -fsanitize=thread
+ */
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..118191e2e00bd07bd4839888d2fb29baec926c60
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/hwasan/halt_on_error-1.c
@@ -0,0 +1,25 @@
+/* Test recovery mode.  */
+/* { dg-do run } */
+/* { dg-options "-fsanitize-recover=hwaddress" } */
+/* { dg-set-target-env-var HWASAN_OPTIONS "halt_on_error=false" } */
+/* { dg-shouldfail "hwasan" } */
+
+#include <string.h>
+
+volatile int ten = 16;
+
+int main() {
+  char x[10];
+  __builtin_memset(x, 0, ten + 1);
+  asm volatile ("" : : : "memory");
+  volatile int res = x[ten];
+  x[ten] = res + 3;
+  res = x[ten];
+  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/g++.dg/hwasan/rvo-handled.c b/gcc/testsuite/g++.dg/hwasan/rvo-handled.c
new file mode 100644
index 0000000000000000000000000000000000000000..6e6934a0be1b0ce14c459555168f6a2590a8ec7f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/hwasan/rvo-handled.c
@@ -0,0 +1,56 @@
+/* { dg-do run } */
+/* TODO Ensure this test has enough optimisation to get RVO. */
+
+#define assert(x) if (!(x)) __builtin_abort ()
+
+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 = &x;
+  return x;
+}
+
+struct big_struct __attribute__ ((noinline))
+unnamed_return_on_stack()
+{
+  return (struct big_struct){
+      .left = 100,
+      .right = 20,
+      .ptr = __builtin_frame_address (0),
+      .big_array = {0}
+  };
+}
+
+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 == &x);
+  struct big_struct y;
+  y = unnamed_return_on_stack();
+  /* Know only running this on AArch64, which means stack grows downwards,
+     We're checking that the frame of the callee function is below the address
+     of this variable, which means that the callee function used RVO.  */
+  assert (y.ptr < (void *)&y);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/hwasan/try-catch-0.cpp b/gcc/testsuite/g++.dg/hwasan/try-catch-0.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d5bbc93564c7f32a029be1a1e071f44188c91da5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/hwasan/try-catch-0.cpp
@@ -0,0 +1,65 @@
+/* { dg-do run } */
+
+/* This version should work just fine.  */
+#include <stdexcept>
+
+char *intermediate_pointer = NULL;
+static void optimization_barrier(void* arg) {
+  asm volatile("" : : "r"(arg) : "memory");
+}
+
+__attribute__((noinline))
+void h() {
+  char x[1000];
+  intermediate_pointer = (void *)&x;
+  optimization_barrier(x);
+  throw std::runtime_error("hello");
+}
+
+__attribute__((noinline))
+void g() {
+  char x[1000];
+  optimization_barrier(x);
+  h();
+  optimization_barrier(x);
+}
+
+__attribute__((noinline))
+void hwasan_read(char *p, int size) {
+  char volatile sink;
+  for (int i = 0; i < size; ++i)
+    sink = p[i];
+}
+
+__attribute__((noinline, no_sanitize("hwaddress"))) void after_catch() {
+  char x[10000];
+  hwasan_read(&x[0], sizeof(x));
+}
+
+
+__attribute__((noinline))
+void f() {
+  char x[1000];
+  try {
+    // Put two tagged frames on the stack, throw an exception from the deepest one.
+    g();
+  } catch (const std::runtime_error &e) {
+    // Put an untagged frame on stack, check that it is indeed untagged.
+    // This relies on exception support zeroing out stack tags.
+    // BAD: tag-mismatch
+    after_catch();
+    // Check that an in-scope stack allocation is still tagged.
+    // This relies on exception support not zeroing too much.
+    hwasan_read(&x[0], sizeof(x));
+#ifdef CLEARED_ACCESS_CATCH
+    return (int)(intermediate_pointer[1]);
+#else
+    return 0;
+#endif
+  }
+  __builtin_abort ();
+}
+
+int main() {
+  f();
+}
diff --git a/gcc/testsuite/g++.dg/hwasan/try-catch-1.cpp b/gcc/testsuite/g++.dg/hwasan/try-catch-1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b124d29d33613794f569646b932b42c958b52348
--- /dev/null
+++ b/gcc/testsuite/g++.dg/hwasan/try-catch-1.cpp
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+
+/* This version should catch the invalid access.  */
+#define CLEARED_ACCESS_CATCH
+#include "try-catch-0.cpp"
+#undef CLEARED_ACCESS_CATCH
diff --git a/gcc/testsuite/gcc.dg/hwasan/aligned-alloc.c b/gcc/testsuite/gcc.dg/hwasan/aligned-alloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..49b317cce7516845944e4b74ece94af0a8570076
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/aligned-alloc.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/*
+   TODO
+    This alignment isn't handled by the sanitizer interceptor alloc.
+    At the moment this program fails at runtime in the libhwasan library.
+
+    LLVM catches this problem at compile-time.
+ */
+
+int
+main ()
+{
+  void *p = __builtin_aligned_alloc (17, 100);
+  if ((unsigned long long)p & 0x10 == 0)
+    return 0;
+  __builtin_abort ();
+}
+
diff --git a/gcc/testsuite/gcc.dg/hwasan/alloca-array-accessible.c b/gcc/testsuite/gcc.dg/hwasan/alloca-array-accessible.c
new file mode 100644
index 0000000000000000000000000000000000000000..c1d7c3bb0d1de7b8e6aa2ba7cf114604583e3ba3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/alloca-array-accessible.c
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+
+#define alloca __builtin_alloca
+
+int __attribute__ ((noinline))
+using_alloca (int num)
+{
+  int retval = 0;
+  int *big_array = 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/gcc.dg/hwasan/alloca-gets-different-tag.c b/gcc/testsuite/gcc.dg/hwasan/alloca-gets-different-tag.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6dcb6fdf4ec535fef475d51de964bcc13337b67
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/alloca-gets-different-tag.c
@@ -0,0 +1,64 @@
+/* { dg-do run } */
+
+/* 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 = 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/gcc.dg/hwasan/alloca-outside-caught.c b/gcc/testsuite/gcc.dg/hwasan/alloca-outside-caught.c
new file mode 100644
index 0000000000000000000000000000000000000000..c794d7900a80ffd42d46ee492b9d53795ba914b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/alloca-outside-caught.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-shouldfail "hwasan" } */
+
+#define alloca __builtin_alloca
+
+int __attribute__ ((noinline))
+check_alloca (int num)
+{
+  volatile int *allocd_array = 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/gcc.dg/hwasan/bitfield-1.c b/gcc/testsuite/gcc.dg/hwasan/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..4cabb1c8a1578bcfb230be40fb54551e010c85b7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/bitfield-1.c
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+
+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/gcc.dg/hwasan/bitfield-2.c b/gcc/testsuite/gcc.dg/hwasan/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4bd53bf8c3e4337d4dccd7f966908f50a9ace08b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/bitfield-2.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-shouldfail "hwasan" } */
+
+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/gcc.dg/hwasan/builtin-special-handling.c b/gcc/testsuite/gcc.dg/hwasan/builtin-special-handling.c
new file mode 100644
index 0000000000000000000000000000000000000000..9458e338f437b64298143f3c81459c1221bf6537
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/builtin-special-handling.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-hwasan_O0 -fdump-tree-hwasan" } */
+
+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
+   builtin_memset.  Second test ensures there was only HWASAN_CHECK (which
+   demonstrates that builtin_strlen was not instrumented).  */
+/* { dg-final { scan-tree-dump-times "HWASAN_CHECK.*builtin_memset" 1 "hwasan1" } } */
+/* TODO It may be that the DejaGNU framework checks the *remaining* output
+   instead of the entire output in the second option.
+   Basically, check this test passes and it may work nicely.  */
+/* { dg-final { scan-tree-dump-times "HWASAN_CHECK" 1 "hwasan1" } } */
diff --git a/gcc/testsuite/gcc.dg/hwasan/check-interface.c b/gcc/testsuite/gcc.dg/hwasan/check-interface.c
new file mode 100644
index 0000000000000000000000000000000000000000..dedb9174726ba031f1727c2617e7c9fc6dc4487d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/check-interface.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/*
+   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.
+
+#include <sanitizer/hwasan_interface.h>
+
+#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/gcc.dg/hwasan/hwasan-poison-optimisation.c b/gcc/testsuite/gcc.dg/hwasan/hwasan-poison-optimisation.c
new file mode 100644
index 0000000000000000000000000000000000000000..6ca716b78f430b726d6211aa4fb271f3a4116588
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/hwasan-poison-optimisation.c
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { 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;
+}
+
+/* TODO This is a pain around LTO.
+   I want to have a test that works for everything (including -flto functions),
+   but can't use any directive that works for both with and without -flto.  */
+/* { dg-final { scan-tree-dump-times "ASAN_POISON" 1 "hwasan1" }  } */
+/* TODO At the moment I simply abort, but in the future we should call some sort of
+   reporting function.
+   There is hence no output to look for right now, but will be in the future.
+*/
+/* { 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/gcc.dg/hwasan/hwasan-thread-access-parent.c b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-access-parent.c
new file mode 100644
index 0000000000000000000000000000000000000000..107430a90245758637e14cca98be4a1cfe4faa13
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-access-parent.c
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "-lpthread" } */
+
+#include <pthread.h>
+
+extern int printf (const char *, ...);
+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 = argument;
+    printf ("(should succeed): first number = %d\n", num[0]);
+    printf ("(now should fail):\n");
+
+    int *othernum = 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/gcc.dg/hwasan/hwasan-thread-basic-failure.c b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-basic-failure.c
new file mode 100644
index 0000000000000000000000000000000000000000..baf4e57884ded6261052c41c94ea5c829372db28
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-basic-failure.c
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { 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>
+
+extern int printf (const char *, ...);
+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/gcc.dg/hwasan/hwasan-thread-clears-stack.c b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-clears-stack.c
new file mode 100644
index 0000000000000000000000000000000000000000..9d07447fae1866bfdf271a6fa2e61a1e3185a48f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-clears-stack.c
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-shouldfail "hwasan" } */
+/* { dg-additional-options "-lpthread" } */
+
+/* This checks the interceptor ABI pthread hooks.  */
+
+#include <pthread.h>
+
+extern int printf (const char *, ...);
+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/gcc.dg/hwasan/hwasan-thread-success.c b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-success.c
new file mode 100644
index 0000000000000000000000000000000000000000..cf8f73495d0da3e734521a488da064f3fe287fcb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/hwasan-thread-success.c
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { 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/gcc.dg/hwasan/hwasan.exp b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp
new file mode 100644
index 0000000000000000000000000000000000000000..f90fd4a8e3e900a36935f6869f011051c1f40882
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp
@@ -0,0 +1,42 @@
+# 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.
+
+# TODO If target is not AArch64, then exit.
+# TODO If target does not have special kernel then exit.
+# TODO Probably best if I just check that compiling some basic file with
+# ~-fsanitize=hwaddress~ works and doesn't crash when using a syscall with a
+# tagged pointer.
+
+# 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/kernel-defaults.c b/gcc/testsuite/gcc.dg/hwasan/kernel-defaults.c
new file mode 100644
index 0000000000000000000000000000000000000000..be021464b8cea548467ac7ea53c67a30b6b79943
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/kernel-defaults.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-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/gcc.dg/hwasan/large-aligned-0.c b/gcc/testsuite/gcc.dg/hwasan/large-aligned-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..aba79e0acf36dd9fa20755d3cfcab29f3cb5625e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/large-aligned-0.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+
+/* 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 __attribute__ ((noinline))
+main ()
+{
+  handle_large_alignment (ARG);
+  return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/hwasan/large-aligned-1.c b/gcc/testsuite/gcc.dg/hwasan/large-aligned-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..abea810bee9d0418493cca72c80d61dfd61a03d7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/large-aligned-1.c
@@ -0,0 +1,13 @@
+/* { dg-do run } */
+/* { 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/gcc.dg/hwasan/macro-definition.c b/gcc/testsuite/gcc.dg/hwasan/macro-definition.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f654f557821f2dbe060e9976fbca7e5770f274c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/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/gcc.dg/hwasan/nested-functions-0.c b/gcc/testsuite/gcc.dg/hwasan/nested-functions-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fce3ec5fd3b092969660f2ee1fa9ac3633747fc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/nested-functions-0.c
@@ -0,0 +1,52 @@
+/* { dg-do run } */
+
+/*
+   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 colour, which means we 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..7d5e80e8a9cb6a1e5a2fb87f78f140c37cd88841
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/nested-functions-1.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { 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..be7942d4fb1bf0dec657396e0bd3ca2f43b78b36
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/nested-functions-2.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { 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/gcc.dg/hwasan/no-sanitize-attribute.c b/gcc/testsuite/gcc.dg/hwasan/no-sanitize-attribute.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5ff4aec06c8bc6c80fe512061ccc8908e321153
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/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/gcc.dg/hwasan/random-frame-tag.c b/gcc/testsuite/gcc.dg/hwasan/random-frame-tag.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dba71bf39558a945d10007b5437651fb7871626
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/random-frame-tag.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-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/gcc.dg/hwasan/setjmp-longjmp-0.c b/gcc/testsuite/gcc.dg/hwasan/setjmp-longjmp-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c7e9c5b3fec8677440b81a2e029427957b359ba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/setjmp-longjmp-0.c
@@ -0,0 +1,53 @@
+/* { dg-do run } */
+
+#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/gcc.dg/hwasan/setjmp-longjmp-1.c b/gcc/testsuite/gcc.dg/hwasan/setjmp-longjmp-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..a32b5063e556f0e45e83d657aa312fb4de860442
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/setjmp-longjmp-1.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { 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/gcc.dg/hwasan/stack-tagging-basic-0.c b/gcc/testsuite/gcc.dg/hwasan/stack-tagging-basic-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..050a3eda7aa421b6b955aedd900f6fbb24a74a61
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/stack-tagging-basic-0.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+
+/* 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 __attribute__ ((noinline))
+main ()
+{
+  using_stack (ARG);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/hwasan/stack-tagging-basic-1.c b/gcc/testsuite/gcc.dg/hwasan/stack-tagging-basic-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..0db6bc4bd220e99bcd695ee93fcc9f4118d09457
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/stack-tagging-basic-1.c
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { 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/gcc.dg/hwasan/stack-tagging-disable.c b/gcc/testsuite/gcc.dg/hwasan/stack-tagging-disable.c
new file mode 100644
index 0000000000000000000000000000000000000000..30f45062d070c482be34f9c824c57f4bd9cc3e10
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/stack-tagging-disable.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-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/gcc.dg/hwasan/vararray-outside-caught.c b/gcc/testsuite/gcc.dg/hwasan/vararray-outside-caught.c
new file mode 100644
index 0000000000000000000000000000000000000000..858bfcd7e596a90c6bd1d68667259a735bb4dce7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/hwasan/vararray-outside-caught.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { 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/gcc.dg/hwasan/very-large-objects.c b/gcc/testsuite/gcc.dg/hwasan/very-large-objects.c
new file mode 100644
index 0000000000000000000000000000000000000000..55265353369540872e8fba4da99d9be92a7ad99b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/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/lib/hwasan-dg.exp b/gcc/testsuite/lib/hwasan-dg.exp
new file mode 100644
index 0000000000000000000000000000000000000000..13cb94b02943f3186cd18f5913bfbd24089af75a
--- /dev/null
+++ b/gcc/testsuite/lib/hwasan-dg.exp
@@ -0,0 +1,352 @@
+# 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;
+    }
+
+    # 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;
+	}
+    }
+
+    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.
+# (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
+
+    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
+
+    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
+}

Attachment: hwasan-patch16.patch.gz
Description: hwasan-patch16.patch.gz


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]