libsanitizer: Add tests

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

gcc/testsuite/ChangeLog:

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

View File

@ -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" } */

View File

@ -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;
}

View File

@ -0,0 +1,66 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-additional-options "--param hwasan-random-frame-tag=1" } */
/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
#include <alloca.h>
/* This testcase checks that `alloca` calls ensure the `__hwasan_generate_tag`
function is called to initialize the base tag. `alloca` calls are treated
differently to standard variables. The prologue/epilogue sequence is
generated mainly based on normal stack-allocated objects.
We want to ensure that though the `alloca` call is not poisoned/unpoisoned
by the prologue and epilogue, the use of them in a given function still
triggers the prologue sequence to emit a call to __hwasan_generate_tag (and
hence that any call to __hwasan_generate_tag is emitted in the unconditional
part of the function code). */
int choice = 0;
int record = 1;
#ifdef __cplusplus
extern "C" {
#endif
__attribute__ ((noinline))
unsigned char
__hwasan_generate_tag ()
{
record = 0;
return 3;
}
#ifdef __cplusplus
}
#endif
__attribute__ ((noinline))
int
generate_tag_was_missed (void)
{
return record;
}
__attribute__((noinline, noclone)) int
foo (char *a)
{
int i, j = 0;
asm volatile ("" : "+r" (a) : : "memory");
for (i = 0; i < 12; i++)
j += a[i];
return j;
}
int
main ()
{
if (choice)
{
char *x = (char *)alloca(100);
foo(x);
}
else
{
char *y = (char *)alloca(20);
foo(y);
}
return generate_tag_was_missed ();
}

View File

@ -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;
}

View File

@ -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\]*.*" } */

View File

@ -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 } */

View File

@ -0,0 +1,3 @@
/* { dg-do compile } */
/* { dg-additional-options "-fsanitize=kernel-address" } */
/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with '-fsanitize=kernel-address'.*" "" { target *-*-* } 0 } */

View File

@ -0,0 +1,3 @@
/* { dg-do compile } */
/* { dg-additional-options "-fsanitize=thread" } */
/* { dg-error ".*'-fsanitize=thread' is incompatible with '-fsanitize=hwaddress'.*" "" { target *-*-* } 0 } */

View File

@ -0,0 +1,3 @@
/* { dg-do compile } */
/* { dg-additional-options "-fsanitize=address" } */
/* { dg-error ".*'-fsanitize=hwaddress' is incompatible with '-fsanitize=address'.*" "" { target *-*-* } 0 } */

View File

@ -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;
}

View File

@ -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:" } */

View File

@ -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" } } */

View File

@ -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;
}

View File

@ -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" } */

View File

@ -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;
}

View File

@ -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\]*.*" } */

View File

@ -0,0 +1,31 @@
/* { dg-do compile } */
/* { dg-additional-options "-fdump-tree-asan" } */
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
/* Only skip the -flto tests without the -flto-partition=none.
With -flto-partition=none we still get a asan1 dump file, without that
parameter we only get the lto dump files (which means scan-tree-dump-times
doesn't work. */
/* { dg-skip-if "" { *-*-* } { "-flto" } { "-flto-partition=none" } } */
typedef __SIZE_TYPE__ size_t;
/* Functions to observe that HWASAN instruments memory builtins in the expected
manner. */
void * __attribute__((noinline))
memset_builtin (void *dest, int value, size_t len)
{
return __builtin_memset (dest, value, len);
}
/* HWASAN avoids strlen because it doesn't know the size of the memory access
until *after* the function call. */
size_t __attribute__ ((noinline))
strlen_builtin (char *element)
{
return __builtin_strlen (element);
}
/* First test ensures that the HWASAN_CHECK was emitted before the
memset. Second test ensures there was only HWASAN_CHECK (which demonstrates
that strlen was not instrumented). */
/* { dg-final { scan-tree-dump-times "HWASAN_CHECK.*memset" 1 "asan1" } } */
/* { dg-final { scan-tree-dump-times "HWASAN_CHECK" 1 "asan1" } } */

View File

@ -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() {}

View File

@ -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\]+.*" } */

View File

@ -0,0 +1,37 @@
/* { dg-do compile { target aarch64-*-* } } */
/* { dg-additional-options "-march=armv8.6-a+sve -fsanitize-address-use-after-scope" } */
#include <arm_sve.h>
__attribute__((noinline, noclone)) int
foo (char *a)
{
int i, j = 0;
asm volatile ("" : "+r" (a) : : "memory");
for (i = 0; i < 12; i++)
j += a[i];
return j;
}
int
main ()
{
int i, j = 0;
for (i = 0; i < 4; i++)
{
char a[12];
__SVInt8_t freq;
/* Just do something with that `freq` variable so that the compiler
doesn't optimise its use away. */
if (__builtin_bcmp (&freq, a, 10))
j += 1;
__builtin_memset (a, 0, sizeof (a));
j += foo (a);
}
return j;
}
/* Just ensure this compiles without giving an ICE.
This is the equivalent of PR 97696 but for HWASAN. HWASAN can handle
poly_int sized variables, and this testcase ensures that we don't ICE when
given them. */

View File

@ -0,0 +1,29 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-options "-fno-builtin-malloc -fno-builtin-free -fno-builtin-memset" } */
/* { dg-shouldfail "hwasan" } */
#ifdef __cplusplus
extern "C" {
#endif
void *memset (void *, int, __SIZE_TYPE__);
void *malloc (__SIZE_TYPE__);
void free (void *);
#ifdef __cplusplus
}
#endif
volatile int ten = 10;
int main(int argc, char **argv) {
char *x = (char*)malloc(10);
memset(x, 0, 10);
int res = x[ten]; /* BOOOM */
free(x);
return res;
}
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* { dg-output "READ of size 1 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "located 0 bytes to the right of 10-byte region.*" } */
/* { dg-output "allocated here:.*" } */
/* { dg-output "#1 0x\[0-9a-f\]+ +in _*main \[^\n\r]*heap-overflow.c:18" } */

View File

@ -0,0 +1,29 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
/* { dg-additional-options "-fdump-tree-asan1 -save-temps" } */
/* Here to check that the ASAN_POISON stuff works just fine.
This mechanism isn't very often used, but I should at least go through the
code-path once in my testfile. */
int
main ()
{
int *ptr = 0;
{
int a;
ptr = &a;
*ptr = 12345;
}
return *ptr;
}
/* { dg-final { scan-tree-dump-times "ASAN_POISON" 1 "asan1" } } */
/* { dg-final { scan-assembler-times "bl\\s*__hwasan_tag_mismatch4" 1 } } */
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -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\]*.*" } */

View File

@ -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\]*.*" } */

View File

@ -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\]*.*" } */

View File

@ -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;
}

View File

@ -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)" } } */

View File

@ -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;
}

View File

@ -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\]*.*" } */

View File

@ -0,0 +1,75 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* Don't really need this option since there are no vararray/alloca objects in
the interesting function, however it never hurts to make doubly sure and
make it explicit that we're checking the alternate approach to deallocation.
*/
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
/* Handling large aligned variables.
Large aligned variables take a different code-path through expand_stack_vars
in cfgexpand.c. This testcase is just to exercise that code-path.
The alternate code-path produces a second base-pointer through some
instructions emitted in the prologue.
This eventually follows a different code path for untagging when not tagging
allocas. The untagging needs to work at the top of the frame, and this
should account for this different base when large aligned variables are
around. */
__attribute__ ((noinline))
void * Ident (void * argument)
{
return argument;
}
#ifndef ALIGNMENT
#define ALIGNMENT
#endif
void __attribute__ ((noinline))
large_alignment_untagging (int num, int *retval, int **big, int **other)
{
int other_array[100] ALIGNMENT;
int big_array[100] __attribute__ ((aligned (32)));
*retval = big_array[num] + other_array[num];
*big = (int*)Ident(big_array);
*other = (int*)Ident(other_array);
}
#ifndef ARG
#define ARG 0
#endif
int global;
int __attribute__ ((noinline))
main ()
{
int retval;
int *big, *other;
large_alignment_untagging (0, &retval, &big, &other);
/* Want to test that both ends of both variables are untagged. */
switch (ARG) {
case 0:
global += big[0];
break;
case 1:
global += big[99];
break;
case 2:
global += other[0];
break;
case 3:
global += other[99];
break;
}
return 0;
}
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -0,0 +1,15 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
#define ARG 1
#include "large-aligned-untagging-0.c"
#undef ARG
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -0,0 +1,15 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
#define ARG 2
#include "large-aligned-untagging-0.c"
#undef ARG
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -0,0 +1,15 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
#define ARG 3
#include "large-aligned-untagging-0.c"
#undef ARG
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -0,0 +1,16 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
#define ARG 0
#define ALIGNMENT __attribute__ ((aligned (32)))
#include "large-aligned-untagging-0.c"
#undef ARG
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -0,0 +1,16 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
#define ARG 1
#define ALIGNMENT __attribute__ ((aligned (32)))
#include "large-aligned-untagging-0.c"
#undef ARG
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -0,0 +1,16 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
#define ARG 2
#define ALIGNMENT __attribute__ ((aligned (32)))
#include "large-aligned-untagging-0.c"
#undef ARG
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -0,0 +1,16 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-shouldfail "hwasan" } */
/* { dg-additional-options "--param hwasan-instrument-allocas=0" } */
#define ARG 3
#define ALIGNMENT __attribute__ ((aligned (32)))
#include "large-aligned-untagging-0.c"
#undef ARG
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* NOTE: This assumes the current tagging mechanism (one at a time from the
base and large aligned variables being handled first). */
/* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "Address 0x\[0-9a-f\]* is located in stack of thread T0.*" } */
/* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */

View File

@ -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" } } */

View File

@ -0,0 +1,12 @@
/* { dg-do compile } */
__attribute__((no_sanitize("hwaddress"))) int
f (int *p, int *q)
{
*p = 42;
return *q;
}
/* Only have one instance of __hwasan, it is __hwasan_init (the module
* constructor) there is no instrumentation in the function. */
/* { dg-final { scan-assembler-times "__hwasan" 1 } } */

View File

@ -0,0 +1,10 @@
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
/* { dg-additional-options "--param hwasan-instrument-mem-intrinsics=0" } */
#include "builtin-special-handling.c"
/* With this flag there should be no checking of builtins.
The above file only has builtins, and hence there should be no checking
after compilation. */
/* { dg-final { scan-assembler-not "__hwasan_(load|store)" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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:" } */

View File

@ -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;
}

View File

@ -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\]*.*" } */

View File

@ -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;
}

View File

@ -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\]*.*" } */

View File

@ -0,0 +1,33 @@
/* { dg-do compile } */
/* { dg-additional-options "--param hwasan-instrument-stack=0" } */
/* No stack tagging => no calls to __hwasan_tag_memory. */
int __attribute__ ((noinline))
accessing_pointers (int *left, int *right)
{
int x = right[2];
left[3] = right[1];
return right[1] + left[2];
}
int __attribute__ ((noinline))
using_stack (int num)
{
int big_array[10];
int other_array[20];
accessing_pointers(other_array, big_array);
return big_array[num];
}
#ifndef ARG
#define ARG 0
#endif
int __attribute__ ((noinline))
main ()
{
using_stack (ARG);
return 0;
}
/* { dg-final { scan-assembler-not "__hwasan_tag_memory" } } */

View File

@ -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;
}

View File

@ -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" } } */

View File

@ -0,0 +1,28 @@
/* { dg-do run } */
/* { dg-require-effective-target hwaddress_exec } */
/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
/* { dg-shouldfail "hwasan" } */
#ifdef __cplusplus
extern "C" {
#endif
void *malloc (__SIZE_TYPE__);
void free (void *);
#ifdef __cplusplus
}
#endif
int main() {
char *x = (char*)malloc(10);
free(x);
return x[5];
}
/* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */
/* { dg-output "READ of size 1 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/\[\[:xdigit:\]\]\[\[:xdigit:\]\] \\(ptr/mem\\) in thread T0.*" } */
/* { dg-output "is located 5 bytes inside of 10-byte region.*" } */
/* { dg-output "freed by thread T0 here:.*" } */
/* { dg-output "#1\[^\n\r]*main\[^\n\r]*use-after-free.c:17.*" } */
/* { dg-output "previously allocated here:.*" } */
/* { dg-output "#1\[^\n\r]*main\[^\n\r]*use-after-free.c:16" } */

View File

@ -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\]*.*" } */

View File

@ -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;
}

View File

@ -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]];
}

View File

@ -3,4 +3,4 @@
int i;
/* { dg-error ".-fsanitize=thread. is incompatible with .-fsanitize=address|kernel-address." "" { target *-*-* } 0 } */
/* { dg-error ".-fsanitize=thread. is incompatible with .-fsanitize=address." "" { target *-*-* } 0 } */

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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\]*.*" } */

View File

@ -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\]*.*" } */

View File

@ -16,6 +16,9 @@
# Return 1 if compilation with -fsanitize=address is error-free for trivial
# code, 0 otherwise.
#
# NOTE: This should only be used between calls to asan_init and asan_finish.
# It is therefore defined here rather than in target-supports.exp.
proc check_effective_target_fsanitize_address {} {
if ![check_no_compiler_messages fsanitize_address executable {
@ -58,33 +61,33 @@ proc asan_include_flags {} {
# (originally from g++.exp)
#
proc asan_link_flags { paths } {
proc asan_link_flags_1 { paths lib } {
global srcdir
global ld_library_path
global shlib_ext
global asan_saved_library_path
global ${lib}_saved_library_path
set gccpath ${paths}
set flags ""
set shlib_ext [get_shlib_extension]
set asan_saved_library_path $ld_library_path
set ${lib}_saved_library_path $ld_library_path
if { $gccpath != "" } {
if { [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.a"]
|| [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.${shlib_ext}"] } {
if { [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.a"]
|| [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.${shlib_ext}"] } {
append flags " -B${gccpath}/libsanitizer/ "
append flags " -B${gccpath}/libsanitizer/asan/ "
append flags " -L${gccpath}/libsanitizer/asan/.libs "
append ld_library_path ":${gccpath}/libsanitizer/asan/.libs"
append flags " -B${gccpath}/libsanitizer/${lib}/ "
append flags " -L${gccpath}/libsanitizer/${lib}/.libs "
append ld_library_path ":${gccpath}/libsanitizer/${lib}/.libs"
}
} else {
global tool_root_dir
set libasan [lookfor_file ${tool_root_dir} libasan]
if { $libasan != "" } {
append flags "-L${libasan} "
append ld_library_path ":${libasan}"
set libdir [lookfor_file ${tool_root_dir} lib${lib}]
if { $libdir != "" } {
append flags "-L${libdir} "
append ld_library_path ":${libdir}"
}
}
@ -93,6 +96,10 @@ proc asan_link_flags { paths } {
return "$flags"
}
proc asan_link_flags { paths } {
return [asan_link_flags_1 $paths asan]
}
#
# asan_init -- called at the start of each subdir of tests
#

View File

@ -0,0 +1,150 @@
# Copyright (C) 2020 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
load_lib asan-dg.exp
# Return 1 if target can compile a binary for hardware address
# sanitization, 0 otherwise.
#
# NOTE: This should only be used between calls to hwasan_init and
# hwasan_finish. It is therefore defined here rather than in
# target-supports.exp.
proc check_effective_target_fsanitize_hwaddress {} {
if ![check_no_compiler_messages fsanitize_hwaddress executable {
int main (void) { return 0; }
}] {
return 0;
}
return 1;
}
# Return 1 if target can compile and run a binary for hardware address
# sanitization, 0 otherwise.
#
# NOTE: This should only be used between calls to hwasan_init and
# hwasan_finish. It is therefore defined here rather than in
# target-supports.exp.
proc check_effective_target_hwaddress_exec {} {
if ![check_runtime hwaddress_exec {
int main (void) { return 0; }
}] {
return 0;
}
return 1;
}
proc hwasan_include_flags {} {
global srcdir
global TESTING_IN_BUILD_TREE
set flags ""
if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } {
return "${flags}"
}
set flags "-I$srcdir/../../libsanitizer/include"
return "$flags"
}
#
# hwasan_link_flags -- compute library path and flags to find libhwasan.
# (implementation in asan-dg.exp)
#
proc hwasan_link_flags { paths } {
return [asan_link_flags_1 $paths hwasan]
}
#
# hwasan_init -- called at the start of each subdir of tests
#
proc hwasan_init { args } {
global TEST_ALWAYS_FLAGS
global ALWAYS_CXXFLAGS
global TOOL_OPTIONS
global hwasan_saved_TEST_ALWAYS_FLAGS
global hwasan_saved_ALWAYS_CXXFLAGS
setenv HWASAN_OPTIONS "random_tags=0"
set link_flags ""
if ![is_remote host] {
if [info exists TOOL_OPTIONS] {
set link_flags "[hwasan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
} else {
set link_flags "[hwasan_link_flags [get_multilibs]]"
}
}
set include_flags "[hwasan_include_flags]"
if [info exists TEST_ALWAYS_FLAGS] {
set hwasan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
}
if [info exists ALWAYS_CXXFLAGS] {
set hwasan_saved_ALWAYS_CXXFLAGS $ALWAYS_CXXFLAGS
set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
set ALWAYS_CXXFLAGS [concat "{additional_flags=-fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags}" $ALWAYS_CXXFLAGS]
} else {
if [info exists TEST_ALWAYS_FLAGS] {
set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags $TEST_ALWAYS_FLAGS"
} else {
set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags"
}
}
}
#
# hwasan_finish -- called at the start of each subdir of tests
#
proc hwasan_finish { args } {
global TEST_ALWAYS_FLAGS
global hwasan_saved_TEST_ALWAYS_FLAGS
global hwasan_saved_ALWAYS_CXXFLAGS
global hwasan_saved_library_path
global ld_library_path
unsetenv HWASAN_OPTIONS
if [info exists hwasan_saved_ALWAYS_CXXFLAGS ] {
set ALWAYS_CXXFLAGS $hwasan_saved_ALWAYS_CXXFLAGS
} else {
if [info exists hwasan_saved_TEST_ALWAYS_FLAGS] {
set TEST_ALWAYS_FLAGS $hwasan_saved_TEST_ALWAYS_FLAGS
} else {
unset TEST_ALWAYS_FLAGS
}
}
if [info exists hwasan_saved_library_path] {
set ld_library_path $hwasan_saved_library_path
set_ld_library_path_env_vars
}
clear_effective_target_cache
}
# Utility for running gtest hwasan emulation under dejagnu, invoked via dg-final.
# Call pass if variable has the desired value, otherwise fail.
#
# Argument 0 handles expected failures and the like
proc hwasan-gtest { args } {
asan-gtest {*}$args
}