diff options
Diffstat (limited to 'test/asan/TestCases/Windows')
74 files changed, 1896 insertions, 0 deletions
diff --git a/test/asan/TestCases/Windows/aligned_mallocs.cc b/test/asan/TestCases/Windows/aligned_mallocs.cc new file mode 100644 index 000000000000..df740b64e51c --- /dev/null +++ b/test/asan/TestCases/Windows/aligned_mallocs.cc @@ -0,0 +1,29 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +#include <windows.h> + +#define CHECK_ALIGNED(ptr,alignment) \ + do { \ + if (((uintptr_t)(ptr) % (alignment)) != 0) \ + return __LINE__; \ + } \ + while(0) + +int main(void) { + int *p = (int*)_aligned_malloc(1024 * sizeof(int), 32); + CHECK_ALIGNED(p, 32); + p[512] = 0; + _aligned_free(p); + + p = (int*)_aligned_malloc(128, 128); + CHECK_ALIGNED(p, 128); + p = (int*)_aligned_realloc(p, 2048 * sizeof(int), 128); + CHECK_ALIGNED(p, 128); + p[1024] = 0; + if (_aligned_msize(p, 128, 0) != 2048 * sizeof(int)) + return __LINE__; + _aligned_free(p); + + return 0; +} diff --git a/test/asan/TestCases/Windows/allocators_sanity.cc b/test/asan/TestCases/Windows/allocators_sanity.cc new file mode 100644 index 000000000000..66a862d7aca5 --- /dev/null +++ b/test/asan/TestCases/Windows/allocators_sanity.cc @@ -0,0 +1,37 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t | FileCheck %s + +#include <malloc.h> +#include <stdio.h> + +int main() { + int *p = (int*)malloc(1024 * sizeof(int)); + p[512] = 0; + free(p); + + p = (int*)malloc(128); + p = (int*)realloc(p, 2048 * sizeof(int)); + p[1024] = 0; + free(p); + + p = (int*)calloc(16, sizeof(int)); + if (p[8] != 0) + return 1; + p[15]++; + if (16 * sizeof(int) != _msize(p)) + return 2; + free(p); + + p = new int; + *p = 42; + delete p; + + p = new int[42]; + p[15]++; + delete [] p; + + printf("All ok\n"); +// CHECK: All ok + + return 0; +} diff --git a/test/asan/TestCases/Windows/beginthreadex.cc b/test/asan/TestCases/Windows/beginthreadex.cc new file mode 100644 index 000000000000..f2b2b4511ad8 --- /dev/null +++ b/test/asan/TestCases/Windows/beginthreadex.cc @@ -0,0 +1,21 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +#include <windows.h> +#include <process.h> + +unsigned WINAPI thread_proc(void *) { + volatile char stack_buffer[42]; + for (int i = 0; i < sizeof(stack_buffer); ++i) + stack_buffer[i] = 42; + return 0; +} + +int main() { + HANDLE thr = (HANDLE)_beginthreadex(NULL, 0, thread_proc, NULL, 0, NULL); + if (thr == 0) + return 1; + if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE)) + return 2; + CloseHandle(thr); +} diff --git a/test/asan/TestCases/Windows/bitfield.cc b/test/asan/TestCases/Windows/bitfield.cc new file mode 100644 index 000000000000..253a759b98df --- /dev/null +++ b/test/asan/TestCases/Windows/bitfield.cc @@ -0,0 +1,21 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +#include <windows.h> + +typedef struct _S { + unsigned int bf1:1; + unsigned int bf2:2; + unsigned int bf3:3; + unsigned int bf4:4; +} S; + +int main(void) { + S *s = (S*)malloc(sizeof(S)); + s->bf1 = 1; + s->bf2 = 2; + s->bf3 = 3; + s->bf4 = 4; + free(s); + return 0; +} diff --git a/test/asan/TestCases/Windows/bitfield_uaf.cc b/test/asan/TestCases/Windows/bitfield_uaf.cc new file mode 100644 index 000000000000..f49d671e3eb3 --- /dev/null +++ b/test/asan/TestCases/Windows/bitfield_uaf.cc @@ -0,0 +1,34 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +typedef struct _S { + unsigned int bf1:1; + unsigned int bf2:2; + unsigned int bf3:3; + unsigned int bf4:4; +} S; + +void make_access(S *s) { + s->bf2 = 2; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: READ of size {{[124]}} at [[ADDR]] +// CHECK: {{#0 .* make_access .*bitfield_uaf.cc}}:[[@LINE-3]] +// CHECK: {{#1 .* main}} +} + +int main(void) { + S *s = (S*)malloc(sizeof(S)); + free(s); +// CHECK: [[ADDR]] is located 0 bytes inside of 4-byte region +// CHECK-LABEL: freed by thread T0 here: +// CHECK: {{#0 .* free }} +// CHECK: {{#1 .* main .*bitfield_uaf.cc}}:[[@LINE-4]] +// CHECK-LABEL: previously allocated by thread T0 here: +// CHECK: {{#0 .* malloc }} +// CHECK: {{#1 .* main .*bitfield_uaf.cc}}:[[@LINE-8]] + make_access(s); + return 0; +} + diff --git a/test/asan/TestCases/Windows/calloc_left_oob.cc b/test/asan/TestCases/Windows/calloc_left_oob.cc new file mode 100644 index 000000000000..459025bde92c --- /dev/null +++ b/test/asan/TestCases/Windows/calloc_left_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + int *buffer = (int*)calloc(42, sizeof(int)); + buffer[-1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*calloc_left_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 4 bytes to the left of 168-byte region +// CHECK: allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* calloc }} +// CHECK-NEXT: {{#1 .* main .*calloc_left_oob.cc}}:[[@LINE-8]] + free(buffer); +} diff --git a/test/asan/TestCases/Windows/calloc_right_oob.cc b/test/asan/TestCases/Windows/calloc_right_oob.cc new file mode 100644 index 000000000000..c976b87d9707 --- /dev/null +++ b/test/asan/TestCases/Windows/calloc_right_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + int *buffer = (int*)calloc(42, sizeof(int)); + buffer[42] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*calloc_right_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes to the right of 168-byte region +// CHECK: allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* calloc }} +// CHECK-NEXT: {{#1 .* main .*calloc_right_oob.cc}}:[[@LINE-8]] + free(buffer); +} diff --git a/test/asan/TestCases/Windows/calloc_uaf.cc b/test/asan/TestCases/Windows/calloc_uaf.cc new file mode 100644 index 000000000000..db5e70741b72 --- /dev/null +++ b/test/asan/TestCases/Windows/calloc_uaf.cc @@ -0,0 +1,20 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + int *buffer = (int*)calloc(42, sizeof(int)); + free(buffer); + buffer[0] = 42; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*calloc_uaf.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region +// CHECK: freed by thread T0 here: +// CHECK-NEXT: {{#0 .* free }} +// CHECK-NEXT: {{#1 .* main .*calloc_uaf.cc}}:[[@LINE-8]] +// CHECK: previously allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* calloc }} +// CHECK-NEXT: {{#1 .* main .*calloc_uaf.cc}}:[[@LINE-12]] +} diff --git a/test/asan/TestCases/Windows/crt_initializers.cc b/test/asan/TestCases/Windows/crt_initializers.cc new file mode 100644 index 000000000000..084f8a45e18a --- /dev/null +++ b/test/asan/TestCases/Windows/crt_initializers.cc @@ -0,0 +1,31 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t | FileCheck %s + +// This is a test for http://code.google.com/p/address-sanitizer/issues/detail?id=305 + +#include <stdio.h> + +typedef void (*FPTR)(); + +// __xi_a and __xi_z are defined in VC/crt/src/crt0dat.c +// and are located in .CRT$XIA and .CRT$XIZ respectively. +extern "C" FPTR __xi_a, __xi_z; + +int main() { + unsigned count = 0; + + // Iterate through CRT initializers. + for (FPTR* it = &__xi_a; it < &__xi_z; ++it) { + if (*it) + count++; + } + + printf("Number of nonzero CRT initializers: %u\n", count); +// CHECK: Number of nonzero CRT initializers +} + +void call_me_maybe() {} + +#pragma data_seg(".CRT$XIB") +// Add an initializer that shouldn't get its own redzone. +FPTR run_on_startup = call_me_maybe; diff --git a/test/asan/TestCases/Windows/demangled_names.cc b/test/asan/TestCases/Windows/demangled_names.cc new file mode 100644 index 000000000000..a528555b1e16 --- /dev/null +++ b/test/asan/TestCases/Windows/demangled_names.cc @@ -0,0 +1,50 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s +// +// This test makes sure ASan symbolizes stack traces the way they are typically +// symbolized on Windows. +#include <malloc.h> + +namespace foo { +// A template function in a namespace. +template<int x> +void bar(char *p) { + *p = x; +} + +// A regular function in a namespace. +void spam(char *p) { + bar<42>(p); +} +} + +// A multi-argument template with a bool template parameter. +template<typename T, bool U> +void baz(T t) { + if (U) + foo::spam(t); +} + +template<typename T> +struct A { + A(T v) { v_ = v; } + ~A(); + char *v_; +}; + +// A destructor of a template class. +template<> +A<char*>::~A() { + baz<char*, true>(v_); +} + +int main() { + char *buffer = (char*)malloc(42); + free(buffer); + A<char*> a(buffer); +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: foo::bar<42> {{.*}}demangled_names.cc +// CHECK: foo::spam {{.*}}demangled_names.cc +// CHECK: baz<char *,1> {{.*}}demangled_names.cc +// CHECK: A<char *>::~A<char *> {{.*}}demangled_names.cc +} diff --git a/test/asan/TestCases/Windows/dll_aligned_mallocs.cc b/test/asan/TestCases/Windows/dll_aligned_mallocs.cc new file mode 100644 index 000000000000..8b2c4d6dd957 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_aligned_mallocs.cc @@ -0,0 +1,34 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: %run %t %t.dll | FileCheck %s + +#include <malloc.h> +#include <stdio.h> + +#define CHECK_ALIGNED(ptr,alignment) \ + do { \ + if (((uintptr_t)(ptr) % (alignment)) != 0) \ + return __LINE__; \ + } \ + while(0) + +extern "C" __declspec(dllexport) +int test_function() { + int *p = (int*)_aligned_malloc(1024 * sizeof(int), 32); + CHECK_ALIGNED(p, 32); + p[512] = 0; + _aligned_free(p); + + p = (int*)_aligned_malloc(128, 128); + CHECK_ALIGNED(p, 128); + p = (int*)_aligned_realloc(p, 2048 * sizeof(int), 128); + CHECK_ALIGNED(p, 128); + p[1024] = 0; + if (_aligned_msize(p, 128, 0) != 2048 * sizeof(int)) + return __LINE__; + _aligned_free(p); + + printf("All ok\n"); +// CHECK: All ok + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_allocators_sanity.cc b/test/asan/TestCases/Windows/dll_allocators_sanity.cc new file mode 100644 index 000000000000..1d31f37ca904 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_allocators_sanity.cc @@ -0,0 +1,39 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: %run %t %t.dll | FileCheck %s + +#include <malloc.h> +#include <stdio.h> + +extern "C" __declspec(dllexport) +int test_function() { + int *p = (int*)malloc(1024 * sizeof(int)); + p[512] = 0; + free(p); + + p = (int*)malloc(128); + p = (int*)realloc(p, 2048 * sizeof(int)); + p[1024] = 0; + free(p); + + p = (int*)calloc(16, sizeof(int)); + if (p[8] != 0) + return 1; + p[15]++; + if (16 * sizeof(int) != _msize(p)) + return 2; + free(p); + + p = new int; + *p = 42; + delete p; + + p = new int[42]; + p[15]++; + delete [] p; + + printf("All ok\n"); +// CHECK: All ok + + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_and_lib.cc b/test/asan/TestCases/Windows/dll_and_lib.cc new file mode 100644 index 000000000000..bddaa32df73b --- /dev/null +++ b/test/asan/TestCases/Windows/dll_and_lib.cc @@ -0,0 +1,19 @@ +// Just make sure we can link an implib into another DLL +// This used to fail between r212699 and r212814. +// RUN: %clang_cl_asan -DCONFIG=1 %s -c -Fo%t.1.obj +// RUN: link /nologo /DLL /OUT:%t.1.dll %t.1.obj %asan_dll_thunk +// RUN: %clang_cl_asan -DCONFIG=2 %s -c -Fo%t.2.obj +// RUN: link /nologo /DLL /OUT:%t.2.dll %t.2.obj %t.1.lib %asan_dll_thunk +// REQUIRES: asan-static-runtime + +#if CONFIG==1 +extern "C" __declspec(dllexport) int f1() { + int x = 0; + return 1; +} +#else +extern "C" __declspec(dllexport) int f2() { + int x = 0; + return 2; +} +#endif diff --git a/test/asan/TestCases/Windows/dll_cerr.cc b/test/asan/TestCases/Windows/dll_cerr.cc new file mode 100644 index 000000000000..8f1a699ba801 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_cerr.cc @@ -0,0 +1,23 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: %run %t %t.dll 2>&1 | FileCheck %s + +// Test that it works correctly even with ICF enabled. +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll -link /OPT:REF /OPT:ICF +// RUN: %run %t %t.dll 2>&1 | FileCheck %s + +#include <iostream> + +extern "C" __declspec(dllexport) +int test_function() { + // Just make sure we can use cout. + std::cout << "All ok\n"; +// CHECK: All ok + + // This line forces a declaration of some global basic_ostream internal object that + // calls memcpy() in its constructor. This doesn't work if __asan_init is not + // called early enough. + std::cout << 42; +// CHECK: 42 + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_host.cc b/test/asan/TestCases/Windows/dll_host.cc new file mode 100644 index 000000000000..d3b4c149d009 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_host.cc @@ -0,0 +1,49 @@ +// This is a host program for DLL tests. +// +// Just make sure we can compile this. +// The actual compile&run sequence is to be done by the DLL tests. +// RUN: %clang_cl_asan -O0 %s -Fe%t +// +// Get the list of ASan wrappers exported by the main module RTL: +// RUN: dumpbin /EXPORTS %t | grep -o "__asan_wrap[^ ]*" | grep -v @ | sort | uniq > %t.exported_wrappers +// +// Get the list of ASan wrappers imported by the DLL RTL: +// RUN: grep INTERCEPT_LIBRARY_FUNCTION %p/../../../../lib/asan/asan_win_dll_thunk.cc | grep -v define | sed "s/.*(\(.*\)).*/__asan_wrap_\1/" | sort | uniq > %t.dll_imports +// +// Now make sure the DLL thunk imports everything: +// RUN: echo +// RUN: echo "=== NOTE === If you see a mismatch below, please update asan_win_dll_thunk.cc" +// RUN: diff %t.dll_imports %t.exported_wrappers +// REQUIRES: asan-static-runtime + +#include <stdio.h> +#include <windows.h> + +int main(int argc, char **argv) { + if (argc != 2) { + printf("Usage: %s [client].dll\n", argv[0]); + return 101; + } + + const char *dll_name = argv[1]; + + HMODULE h = LoadLibrary(dll_name); + if (!h) { + printf("Could not load DLL: %s (code: %lu)!\n", + dll_name, GetLastError()); + return 102; + } + + typedef int (*test_function)(); + test_function gf = (test_function)GetProcAddress(h, "test_function"); + if (!gf) { + printf("Could not locate test_function in the DLL!\n"); + FreeLibrary(h); + return 103; + } + + int ret = gf(); + + FreeLibrary(h); + return ret; +} diff --git a/test/asan/TestCases/Windows/dll_intercept_memchr.cc b/test/asan/TestCases/Windows/dll_intercept_memchr.cc new file mode 100644 index 000000000000..1435bdc50127 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_intercept_memchr.cc @@ -0,0 +1,21 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <string.h> + +extern "C" __declspec(dllexport) +int test_function() { + char buff[6] = "Hello"; + + memchr(buff, 'z', 7); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: READ of size 7 at [[ADDR]] thread T0 +// CHECK-NEXT: __asan_wrap_memchr +// CHECK-NEXT: memchr +// CHECK-NEXT: test_function {{.*}}dll_intercept_memchr.cc:[[@LINE-5]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame +// CHECK-NEXT: test_function {{.*}}dll_intercept_memchr.cc +// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc new file mode 100644 index 000000000000..736e6969d521 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc @@ -0,0 +1,32 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +// Test that it works correctly even with ICF enabled. +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll -link /OPT:REF /OPT:ICF +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> + +extern "C" __declspec(dllexport) +int test_function() { + char buff1[6] = "Hello", buff2[5]; + + memcpy(buff2, buff1, 5); + if (buff1[2] != buff2[2]) + return 2; + printf("Initial test OK\n"); + fflush(0); +// CHECK: Initial test OK + + memcpy(buff2, buff1, 6); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 6 at [[ADDR]] thread T0 +// CHECK-NEXT: __asan_{{.*}}memcpy +// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy.cc:[[@LINE-4]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame +// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy.cc +// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc new file mode 100644 index 000000000000..c5f44df3faaf --- /dev/null +++ b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc @@ -0,0 +1,34 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> + +void call_memcpy(void* (*f)(void *, const void *, size_t), + void *a, const void *b, size_t c) { + f(a, b, c); +} + +extern "C" __declspec(dllexport) +int test_function() { + char buff1[6] = "Hello", buff2[5]; + + call_memcpy(&memcpy, buff2, buff1, 5); + if (buff1[2] != buff2[2]) + return 2; + printf("Initial test OK\n"); + fflush(0); +// CHECK: Initial test OK + + call_memcpy(&memcpy, buff2, buff1, 6); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 6 at [[ADDR]] thread T0 +// CHECK-NEXT: __asan_{{.*}}memcpy +// CHECK-NEXT: call_memcpy +// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy_indirect.cc:[[@LINE-5]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame +// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy_indirect.cc +// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_intercept_memset.cc b/test/asan/TestCases/Windows/dll_intercept_memset.cc new file mode 100644 index 000000000000..d4be376f2458 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_intercept_memset.cc @@ -0,0 +1,32 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +// Test that it works correctly even with ICF enabled. +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll -link /OPT:REF /OPT:ICF +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> + +extern "C" __declspec(dllexport) +int test_function() { + char buff[5] = "aaaa"; + + memset(buff, 'b', 5); + if (buff[2] != 'b') + return 2; + printf("Initial test OK\n"); + fflush(0); +// CHECK: Initial test OK + + memset(buff, 'c', 6); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 6 at [[ADDR]] thread T0 +// CHECK-NEXT: __asan_memset +// CHECK-NEXT: test_function {{.*}}dll_intercept_memset.cc:[[@LINE-4]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame +// CHECK-NEXT: test_function {{.*}}dll_intercept_memset.cc +// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_intercept_strlen.cc b/test/asan/TestCases/Windows/dll_intercept_strlen.cc new file mode 100644 index 000000000000..f41d47858bee --- /dev/null +++ b/test/asan/TestCases/Windows/dll_intercept_strlen.cc @@ -0,0 +1,28 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> + +extern "C" __declspec(dllexport) +int test_function() { + char str[] = "Hello!"; + if (6 != strlen(str)) + return 1; + printf("Initial test OK\n"); + fflush(0); +// CHECK: Initial test OK + + str[6] = '!'; // Removes '\0' at the end! + int len = strlen(str); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// FIXME: Should be READ of size 1, see issue 155. +// CHECK: READ of size {{[0-9]+}} at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .*}}strlen +// CHECK-NEXT: {{#1 .* test_function .*}}dll_intercept_strlen.cc:[[@LINE-5]] +// +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame +// CHECK-NEXT: test_function {{.*}}dll_intercept_strlen.cc: + return len > 42; +} diff --git a/test/asan/TestCases/Windows/dll_large_function.cc b/test/asan/TestCases/Windows/dll_large_function.cc new file mode 100644 index 000000000000..039d01f84ba5 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_large_function.cc @@ -0,0 +1,12 @@ +// Make sure we can link a DLL with large functions which would mean +// functions such as __asan_loadN and __asan_storeN will be called +// from the DLL. We simulate the large function with +// -mllvm -asan-instrumentation-with-call-threshold=0. +// RUN: %clang_cl_asan %s -c -Fo%t.obj -mllvm -asan-instrumentation-with-call-threshold=0 +// RUN: link /nologo /DLL /OUT:%t.dll %t.obj %asan_dll_thunk +// REQUIRES: asan-static-runtime + +void f(long* foo, long* bar) { + // One load and one store + *foo = *bar; +} diff --git a/test/asan/TestCases/Windows/dll_malloc_left_oob.cc b/test/asan/TestCases/Windows/dll_malloc_left_oob.cc new file mode 100644 index 000000000000..0653ea45f6ef --- /dev/null +++ b/test/asan/TestCases/Windows/dll_malloc_left_oob.cc @@ -0,0 +1,23 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <malloc.h> +extern "C" __declspec(dllexport) +int test_function() { + char *buffer = (char*)malloc(42); + buffer[-1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-3]] +// CHECK-NEXT: main {{.*}}dll_host.cc +// +// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region +// CHECK-LABEL: allocated by thread T0 here: +// CHECK-NEXT: malloc +// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-10]] +// CHECK-NEXT: main {{.*}}dll_host.cc +// CHECK-LABEL: SUMMARY + free(buffer); + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_malloc_uaf.cc b/test/asan/TestCases/Windows/dll_malloc_uaf.cc new file mode 100644 index 000000000000..b286380ac445 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_malloc_uaf.cc @@ -0,0 +1,28 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <malloc.h> + +extern "C" __declspec(dllexport) +int test_function() { + int *buffer = (int*)malloc(42); + free(buffer); + buffer[0] = 42; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-3]] +// CHECK-NEXT: main {{.*}}dll_host +// +// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region +// CHECK-LABEL: freed by thread T0 here: +// CHECK-NEXT: free +// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-10]] +// CHECK-NEXT: main {{.*}}dll_host +// +// CHECK-LABEL: previously allocated by thread T0 here: +// CHECK-NEXT: malloc +// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-16]] +// CHECK-NEXT: main {{.*}}dll_host + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_noreturn.cc b/test/asan/TestCases/Windows/dll_noreturn.cc new file mode 100644 index 000000000000..6ec90725145f --- /dev/null +++ b/test/asan/TestCases/Windows/dll_noreturn.cc @@ -0,0 +1,28 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <process.h> + +void noreturn_f() { + int subscript = -1; + char buffer[42]; + buffer[subscript] = 42; + _exit(1); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc:[[@LINE-4]] +// CHECK-NEXT: test_function {{.*}}dll_noreturn.cc +// CHECK-NEXT: main {{.*}}dll_host.cc +// +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame +// CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc +// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable +// CHECK-LABEL: SUMMARY +} + +extern "C" __declspec(dllexport) +int test_function() { + noreturn_f(); + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_null_deref.cc b/test/asan/TestCases/Windows/dll_null_deref.cc new file mode 100644 index 000000000000..0fb18de29163 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_null_deref.cc @@ -0,0 +1,18 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +__attribute__((noinline)) +static void NullDeref(int *ptr) { + // CHECK: ERROR: AddressSanitizer: access-violation on unknown address + // CHECK: {{0x0*000.. .*pc 0x.*}} + ptr[10]++; // BOOM +} + +extern "C" __declspec(dllexport) +int test_function() { + NullDeref((int*)0); + // CHECK: {{ #1 0x.* in test_function .*\dll_null_deref.cc:}}[[@LINE-1]] + // CHECK: AddressSanitizer can not provide additional info. + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc b/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc new file mode 100644 index 000000000000..736ce80cc32a --- /dev/null +++ b/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc @@ -0,0 +1,25 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +extern "C" __declspec(dllexport) +int test_function() { + char *buffer = new char[42]; + buffer[-1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_left_oob.cc:[[@LINE-3]] +// CHECK-NEXT: main {{.*}}dll_host.cc +// +// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region +// CHECK-LABEL: allocated by thread T0 here: +// FIXME: Should get rid of the malloc/free frames called from the inside of +// operator new/delete in DLLs when using -MT CRT. +// FIXME: The 'operator new' frame should have []. +// CHECK: operator new +// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_left_oob.cc:[[@LINE-13]] +// CHECK-NEXT: main {{.*}}dll_host.cc +// CHECK-LABEL: SUMMARY + delete [] buffer; + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc new file mode 100644 index 000000000000..8306a737bfff --- /dev/null +++ b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc @@ -0,0 +1,33 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +struct C { + int x; + ~C() {} +}; + +extern "C" __declspec(dllexport) +int test_function() { + C *buffer = new C[42]; + buffer[-2].x = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_with_dtor_left_oob.cc:[[@LINE-3]] +// CHECK-NEXT: main {{.*}}dll_host.cc +// +// FIXME: Currently it says "4 bytes ... left of 172-byte region", +// should be "8 bytes ... left of 168-byte region", see +// https://code.google.com/p/address-sanitizer/issues/detail?id=314 +// CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region +// FIXME: Should get rid of the malloc/free frames called from the inside of +// operator new/delete in DLLs when using -MT CRT. +// FIXME: The operator new frame should have []. +// CHECK-LABEL: allocated by thread T0 here: +// CHECK: operator new +// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_with_dtor_left_oob.cc:[[@LINE-16]] +// CHECK-NEXT: main {{.*}}dll_host.cc +// CHECK-LABEL: SUMMARY + delete [] buffer; + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_poison_unpoison.cc b/test/asan/TestCases/Windows/dll_poison_unpoison.cc new file mode 100644 index 000000000000..d486cb122251 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_poison_unpoison.cc @@ -0,0 +1,35 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <sanitizer/asan_interface.h> + +void should_not_crash(volatile char *c) { + *c = 42; +} + +void should_crash(volatile char *c) { + *c = 42; +} + +extern "C" __declspec(dllexport) +int test_function() { + char buffer[256]; + should_not_crash(&buffer[0]); + __asan_poison_memory_region(buffer, 128); + should_not_crash(&buffer[192]); + __asan_unpoison_memory_region(buffer, 64); + should_not_crash(&buffer[32]); + + should_crash(&buffer[96]); +// CHECK: AddressSanitizer: use-after-poison on address [[ADDR:0x[0-9a-f]+]] +// CHECK-NEXT: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: should_crash {{.*}}\dll_poison_unpoison.cc +// CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc:[[@LINE-4]] +// CHECK-NEXT: main +// +// CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame +// CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc +// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] is inside this variable + return 0; +} diff --git a/test/asan/TestCases/Windows/dll_seh.cc b/test/asan/TestCases/Windows/dll_seh.cc new file mode 100644 index 000000000000..6e4c724e504d --- /dev/null +++ b/test/asan/TestCases/Windows/dll_seh.cc @@ -0,0 +1,60 @@ +// Clang doesn't support SEH on Windows yet, so for the time being we +// build this program in two parts: the code with SEH is built with CL, +// the rest is built with Clang. This represents the typical scenario when we +// build a large project using "clang-cl -fallback -fsanitize=address". +// +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// +// Check both -GS and -GS- builds: +// RUN: cl -LD -c %s -Fo%t.obj +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll %t.obj +// RUN: %run %t %t.dll +// +// RUN: cl -LD -GS- -c %s -Fo%t.obj +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll %t.obj +// RUN: %run %t %t.dll + +#include <windows.h> +#include <assert.h> +#include <stdio.h> + +// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are +// supported and we don't need to use CL. +extern "C" bool __asan_address_is_poisoned(void *p); + +void ThrowAndCatch(); + +#if !defined(__clang__) +__declspec(noinline) +void Throw() { + int local, zero = 0; + fprintf(stderr, "Throw: %p\n", &local); + local = 5 / zero; +} + +__declspec(noinline) +void ThrowAndCatch() { + int local; + __try { + Throw(); + } __except(EXCEPTION_EXECUTE_HANDLER) { + fprintf(stderr, "__except: %p\n", &local); + } +} +#else + +extern "C" __declspec(dllexport) +int test_function() { + char x[32]; + fprintf(stderr, "Before: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + assert(__asan_address_is_poisoned(x + 32)); + ThrowAndCatch(); + fprintf(stderr, "After: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + // FIXME: Invert this assertion once we fix + // https://code.google.com/p/address-sanitizer/issues/detail?id=258 + assert(!__asan_address_is_poisoned(x + 32)); + return 0; +} +#endif diff --git a/test/asan/TestCases/Windows/dll_stack_use_after_return.cc b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc new file mode 100644 index 000000000000..6cd74c265b8f --- /dev/null +++ b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc @@ -0,0 +1,28 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 not %run %t %t.dll 2>&1 | FileCheck %s + +#include <malloc.h> + +char *x; + +void foo() { + char stack_buffer[42]; + x = &stack_buffer[13]; +} + +extern "C" __declspec(dllexport) +int test_function() { + foo(); + *x = 42; +// CHECK: AddressSanitizer: stack-use-after-return +// CHECK: WRITE of size 1 at [[ADDR:.*]] thread T0 +// CHECK-NEXT: test_function {{.*}}dll_stack_use_after_return.cc:[[@LINE-3]] +// CHECK-NEXT: main +// +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame +// CHECK-NEXT: #0 {{.*}} foo {{.*}}dll_stack_use_after_return.cc +// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable + return 0; +} + diff --git a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc new file mode 100644 index 000000000000..8f53623419ce --- /dev/null +++ b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc @@ -0,0 +1,36 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s + +#include <windows.h> +#include <malloc.h> + +DWORD WINAPI thread_proc(void *context) { + int subscript = -1; + char stack_buffer[42]; + stack_buffer[subscript] = 42; +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T1 +// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-3]] +// +// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset [[OFFSET:.*]] in frame +// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc +// +// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] underflows this variable + + return 0; +} + +extern "C" __declspec(dllexport) +int test_function() { + HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL); +// CHECK-LABEL: Thread T1 created by T0 here: +// CHECK: test_function {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-2]] +// CHECK-NEXT: main {{.*}}dll_host.cc +// CHECK-LABEL: SUMMARY + if (thr == 0) + return 1; + if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE)) + return 2; + return 0; +} diff --git a/test/asan/TestCases/Windows/double_free.cc b/test/asan/TestCases/Windows/double_free.cc new file mode 100644 index 000000000000..18a9fcb44a75 --- /dev/null +++ b/test/asan/TestCases/Windows/double_free.cc @@ -0,0 +1,21 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + int *x = (int*)malloc(42 * sizeof(int)); + free(x); + free(x); +// CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]] +// CHECK-NEXT: {{#0 .* free }} +// CHECK-NEXT: {{#1 .* main .*double_free.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region +// CHECK-LABEL: freed by thread T0 here: +// CHECK-NEXT: {{#0 .* free }} +// CHECK-NEXT: {{#1 .* main .*double_free.cc}}:[[@LINE-8]] +// CHECK-LABEL: previously allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* malloc }} +// CHECK-NEXT: {{#1 .* main .*double_free.cc}}:[[@LINE-12]] + return 0; +} diff --git a/test/asan/TestCases/Windows/double_operator_delete.cc b/test/asan/TestCases/Windows/double_operator_delete.cc new file mode 100644 index 000000000000..eae4a64c2b92 --- /dev/null +++ b/test/asan/TestCases/Windows/double_operator_delete.cc @@ -0,0 +1,25 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + int *x = new int[42]; + delete [] x; + delete [] x; +// CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]] +// FIXME: The 'operator delete' frame should have []. +// CHECK-NEXT: {{#0 .* operator delete}} +// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-4]] +// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region +// CHECK-LABEL: freed by thread T0 here: +// FIXME: The 'operator delete' frame should have []. +// CHECK-NEXT: {{#0 .* operator delete}} +// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-10]] +// CHECK-LABEL: previously allocated by thread T0 here: +// FIXME: The 'operator new' frame should have []. +// CHECK-NEXT: {{#0 .* operator new}} +// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-15]] + return 0; +} + diff --git a/test/asan/TestCases/Windows/global_const_string.cc b/test/asan/TestCases/Windows/global_const_string.cc new file mode 100644 index 000000000000..8c147c917c88 --- /dev/null +++ b/test/asan/TestCases/Windows/global_const_string.cc @@ -0,0 +1,12 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t | FileCheck %s + +#include <windows.h> +#include <stdio.h> + +int main(void) { + static const char *foo = "foobarspam"; + printf("Global string is `%s`\n", foo); +// CHECK: Global string is `foobarspam` + return 0; +} diff --git a/test/asan/TestCases/Windows/global_const_string_oob.cc b/test/asan/TestCases/Windows/global_const_string_oob.cc new file mode 100644 index 000000000000..b39e3dbb3b4e --- /dev/null +++ b/test/asan/TestCases/Windows/global_const_string_oob.cc @@ -0,0 +1,20 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> +#include <stdio.h> + +extern "C" const char *foo = "foobarspam"; + +int main(void) { + if (foo[16]) + printf("Boo\n"); +// CHECK-NOT: Boo +// CHECK: AddressSanitizer: global-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: READ of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*global_const_string_oob.cc:}}[[@LINE-5]] +// CHECK: [[ADDR]] is located 5 bytes to the right of global variable [[STR:.*]] defined in {{'.*global_const_string_oob.cc:7:.*' .*}} of size 11 +// CHECK: [[STR]] is ascii string 'foobarspam' + return 0; +} + diff --git a/test/asan/TestCases/Windows/hello_world.cc b/test/asan/TestCases/Windows/hello_world.cc new file mode 100644 index 000000000000..400ca1b3eacc --- /dev/null +++ b/test/asan/TestCases/Windows/hello_world.cc @@ -0,0 +1,9 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t | FileCheck %s + +#include <stdio.h> + +int main() { + printf("Hello, world!\n"); +// CHECK: Hello, world! +} diff --git a/test/asan/TestCases/Windows/intercept_memcpy.cc b/test/asan/TestCases/Windows/intercept_memcpy.cc new file mode 100644 index 000000000000..9ee984b1873d --- /dev/null +++ b/test/asan/TestCases/Windows/intercept_memcpy.cc @@ -0,0 +1,31 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> + +void call_memcpy(void* (*f)(void *, const void *, size_t), + void *a, const void *b, size_t c) { + f(a, b, c); +} + +int main() { + char buff1[6] = "Hello", buff2[5]; + + call_memcpy(&memcpy, buff2, buff1, 5); + if (buff1[2] != buff2[2]) + return 2; + printf("Initial test OK\n"); + fflush(0); +// CHECK: Initial test OK + + call_memcpy(&memcpy, buff2, buff1, 6); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 6 at [[ADDR]] thread T0 +// CHECK-NEXT: __asan_{{.*}}memcpy +// CHECK-NEXT: call_memcpy +// CHECK-NEXT: main {{.*}}intercept_memcpy.cc:[[@LINE-5]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame +// CHECK-NEXT: #0 {{.*}} main +// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable +} diff --git a/test/asan/TestCases/Windows/intercept_strdup.cc b/test/asan/TestCases/Windows/intercept_strdup.cc new file mode 100644 index 000000000000..edb1f2f99245 --- /dev/null +++ b/test/asan/TestCases/Windows/intercept_strdup.cc @@ -0,0 +1,27 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> +#include <malloc.h> + +int main() { + char *ptr = _strdup("Hello"); + int subscript = 1; + ptr[subscript] = '3'; + printf("%s\n", ptr); + fflush(0); +// CHECK: H3llo + + subscript = -1; + ptr[subscript] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK: {{#0 .* main .*}}intercept_strdup.cc:[[@LINE-3]] +// CHECK: [[ADDR]] is located 1 bytes to the left of 6-byte region +// CHECK: allocated by thread T0 here: +// CHECK: {{#0 .* malloc }} +// CHECK: {{#1 .*strdup}} +// CHECK: {{#2 .* main .*}}intercept_strdup.cc:[[@LINE-16]] + free(ptr); +} diff --git a/test/asan/TestCases/Windows/intercept_strlen.cc b/test/asan/TestCases/Windows/intercept_strlen.cc new file mode 100644 index 000000000000..928a286bedfa --- /dev/null +++ b/test/asan/TestCases/Windows/intercept_strlen.cc @@ -0,0 +1,27 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> + +int main() { + char str[] = "Hello"; + if (5 != strlen(str)) + return 1; + + printf("Initial test OK\n"); + fflush(0); +// CHECK: Initial test OK + + str[5] = '!'; // Losing '\0' at the end. + int len = strlen(str); +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// FIXME: Should be READ of size 1, see issue 155. +// CHECK: READ of size {{[0-9]+}} at [[ADDR]] thread T0 +// CHECK: strlen +// CHECK-NEXT: main {{.*}}intercept_strlen.cc:[[@LINE-5]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame +// CHECK-NEXT: main {{.*}}intercept_strlen.cc +// CHECK: 'str' <== Memory access at offset {{.*}} overflows this variable + return len < 6; +} diff --git a/test/asan/TestCases/Windows/lit.local.cfg b/test/asan/TestCases/Windows/lit.local.cfg new file mode 100644 index 000000000000..13ef6d428251 --- /dev/null +++ b/test/asan/TestCases/Windows/lit.local.cfg @@ -0,0 +1,14 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +# We only run a small set of tests on Windows for now. +# Override the parent directory's "unsupported" decision until we can handle +# all of its tests. +if root.host_os in ['Windows']: + config.unsupported = False +else: + config.unsupported = True diff --git a/test/asan/TestCases/Windows/longjmp.cc b/test/asan/TestCases/Windows/longjmp.cc new file mode 100644 index 000000000000..443933e8ab62 --- /dev/null +++ b/test/asan/TestCases/Windows/longjmp.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx_asan -O %s -o %t && %run %t + +// FIXME: merge this with the common longjmp test when we can run common +// tests on Windows. + +#include <assert.h> +#include <setjmp.h> +#include <stdio.h> +#include <sanitizer/asan_interface.h> + +static jmp_buf buf; + +int main() { + char x[32]; + fprintf(stderr, "\nTestLongJmp\n"); + fprintf(stderr, "Before: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + assert(__asan_address_is_poisoned(x + 32)); + if (0 == setjmp(buf)) + longjmp(buf, 1); + fprintf(stderr, "After: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + // FIXME: Invert this assertion once we fix + // https://code.google.com/p/address-sanitizer/issues/detail?id=258 + assert(!__asan_address_is_poisoned(x + 32)); +} diff --git a/test/asan/TestCases/Windows/malloc_left_oob.cc b/test/asan/TestCases/Windows/malloc_left_oob.cc new file mode 100644 index 000000000000..ec133c393da2 --- /dev/null +++ b/test/asan/TestCases/Windows/malloc_left_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + char *buffer = (char*)malloc(42); + buffer[-1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*malloc_left_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region +// CHECK: allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* malloc }} +// CHECK-NEXT: {{#1 .* main .*malloc_left_oob.cc}}:[[@LINE-8]] + free(buffer); +} diff --git a/test/asan/TestCases/Windows/malloc_right_oob.cc b/test/asan/TestCases/Windows/malloc_right_oob.cc new file mode 100644 index 000000000000..9975316d3e02 --- /dev/null +++ b/test/asan/TestCases/Windows/malloc_right_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + char *buffer = (char*)malloc(42); + buffer[42] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*malloc_right_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes to the right of 42-byte region +// CHECK: allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* malloc }} +// CHECK-NEXT: {{#1 .* main .*malloc_right_oob.cc}}:[[@LINE-8]] + free(buffer); +} diff --git a/test/asan/TestCases/Windows/malloc_uaf.cc b/test/asan/TestCases/Windows/malloc_uaf.cc new file mode 100644 index 000000000000..f58478947bf4 --- /dev/null +++ b/test/asan/TestCases/Windows/malloc_uaf.cc @@ -0,0 +1,20 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + char *buffer = (char*)malloc(42); + free(buffer); + buffer[0] = 42; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*malloc_uaf.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region +// CHECK: freed by thread T0 here: +// CHECK-NEXT: {{#0 .* free }} +// CHECK-NEXT: {{#1 .* main .*malloc_uaf.cc}}:[[@LINE-8]] +// CHECK: previously allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* malloc }} +// CHECK-NEXT: {{#1 .* main .*malloc_uaf.cc}}:[[@LINE-12]] +} diff --git a/test/asan/TestCases/Windows/null_deref.cc b/test/asan/TestCases/Windows/null_deref.cc new file mode 100644 index 000000000000..202000f59db7 --- /dev/null +++ b/test/asan/TestCases/Windows/null_deref.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// FIXME: merge this with the common null_deref test when we can run common +// tests on Windows. + +__attribute__((noinline)) +static void NullDeref(int *ptr) { + // CHECK: ERROR: AddressSanitizer: access-violation on unknown address + // CHECK: {{0x0*000.. .*pc 0x.*}} + ptr[10]++; // BOOM +} +int main() { + NullDeref((int*)0); + // CHECK: {{ #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]] + // CHECK: AddressSanitizer can not provide additional info. +} diff --git a/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc b/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc new file mode 100644 index 000000000000..62fe544ae545 --- /dev/null +++ b/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc @@ -0,0 +1,40 @@ +// Make sure everything works even if the main module doesn't have any stack +// variables, thus doesn't explicitly reference any symbol exported by the +// runtime thunk. +// +// RUN: %clang_cl_asan -LD -O0 -DDLL1 %s -Fe%t1.dll +// RUN: %clang_cl_asan -LD -O0 -DDLL2 %s -Fe%t2.dll +// RUN: %clang_cl_asan -O0 -DEXE %s %t1.lib %t2.lib -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> +#include <string.h> + +extern "C" { +#if defined(EXE) +__declspec(dllimport) void foo1(); +__declspec(dllimport) void foo2(); + +int main() { + foo1(); + foo2(); +} +#elif defined(DLL1) +__declspec(dllexport) void foo1() {} +#elif defined(DLL2) +__attribute__((noinline)) +static void NullDeref(int *ptr) { + // CHECK: ERROR: AddressSanitizer: access-violation on unknown address + // CHECK: {{0x0*000.. .*pc 0x.*}} + ptr[10]++; // BOOM +} + +__declspec(dllexport) void foo2() { + NullDeref((int*)0); + // CHECK: {{ #1 0x.* in foo2.*null_deref_multiple_dlls.cc:}}[[@LINE-1]] + // CHECK: AddressSanitizer can not provide additional info. +} +#else +# error oops! +#endif +} diff --git a/test/asan/TestCases/Windows/operator_array_new_left_oob.cc b/test/asan/TestCases/Windows/operator_array_new_left_oob.cc new file mode 100644 index 000000000000..20a0f1927e5b --- /dev/null +++ b/test/asan/TestCases/Windows/operator_array_new_left_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +int main() { + char *buffer = new char[42]; + buffer[-1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*operator_array_new_left_oob.cc}}:[[@LINE-3]] +// +// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region +// CHECK-LABEL: allocated by thread T0 here: +// FIXME: The 'operator new' frame should have []. +// CHECK-NEXT: {{#0 .* operator new}} +// CHECK-NEXT: {{#1 .* main .*operator_array_new_left_oob.cc}}:[[@LINE-10]] + delete [] buffer; +} diff --git a/test/asan/TestCases/Windows/operator_array_new_right_oob.cc b/test/asan/TestCases/Windows/operator_array_new_right_oob.cc new file mode 100644 index 000000000000..23775ef6066e --- /dev/null +++ b/test/asan/TestCases/Windows/operator_array_new_right_oob.cc @@ -0,0 +1,18 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +int main() { + char *buffer = new char[42]; + buffer[42] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK: {{#0 .* main .*operator_array_new_right_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes to the right of 42-byte region +// CHECK: allocated by thread T0 here: +// FIXME: The 'operator new' frame should have []. +// CHECK: {{#0 .* operator new}} +// CHECK: {{#1 .* main .*operator_array_new_right_oob.cc}}:[[@LINE-9]] + delete [] buffer; +} diff --git a/test/asan/TestCases/Windows/operator_array_new_uaf.cc b/test/asan/TestCases/Windows/operator_array_new_uaf.cc new file mode 100644 index 000000000000..b638ef1df415 --- /dev/null +++ b/test/asan/TestCases/Windows/operator_array_new_uaf.cc @@ -0,0 +1,24 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +int main() { + char *buffer = new char[42]; + delete [] buffer; + buffer[0] = 42; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK: {{#0 .* main .*operator_array_new_uaf.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region +// CHECK-LABEL: freed by thread T0 here: +// FIXME: The 'operator delete' frame should have []. +// CHECK: {{#0 .* operator delete}} +// CHECK: {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-9]] +// CHECK-LABEL: previously allocated by thread T0 here: +// FIXME: The 'operator new' frame should have []. +// CHECK: {{#0 .* operator new}} +// CHECK: {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-14]] + return 0; +} + diff --git a/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc new file mode 100644 index 000000000000..63f2929bd89b --- /dev/null +++ b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc @@ -0,0 +1,25 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +struct C { + int x; + ~C() {} +}; + +int main() { + C *buffer = new C[42]; + buffer[-2].x = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*operator_array_new_with_dtor_left_oob.cc}}:[[@LINE-3]] +// +// FIXME: Currently it says "4 bytes ... left of 172-byte region", +// should be "8 bytes ... left of 168-byte region", see +// https://code.google.com/p/address-sanitizer/issues/detail?id=314 +// CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region +// CHECK-LABEL: allocated by thread T0 here: +// FIXME: The 'operator new' frame should have []. +// CHECK-NEXT: {{#0 .* operator new}} +// CHECK-NEXT: {{#1 .* main .*operator_array_new_with_dtor_left_oob.cc}}:[[@LINE-13]] + delete [] buffer; +} diff --git a/test/asan/TestCases/Windows/operator_delete_wrong_argument.cc b/test/asan/TestCases/Windows/operator_delete_wrong_argument.cc new file mode 100644 index 000000000000..c3e7daca55b0 --- /dev/null +++ b/test/asan/TestCases/Windows/operator_delete_wrong_argument.cc @@ -0,0 +1,12 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +int main() { + int *x = new int[42]; + delete (x + 1); +// CHECK: AddressSanitizer: attempting free on address which was not malloc()-ed +// CHECK: {{#0 0x.* operator delete }} +// CHECK: {{#1 .* main .*operator_delete_wrong_argument.cc}}:[[@LINE-3]] +} diff --git a/test/asan/TestCases/Windows/operator_new_left_oob.cc b/test/asan/TestCases/Windows/operator_new_left_oob.cc new file mode 100644 index 000000000000..c077f11d68f9 --- /dev/null +++ b/test/asan/TestCases/Windows/operator_new_left_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +int main() { + char *buffer = new char; + buffer[-1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK: {{#0 .* main .*operator_new_left_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 1 bytes to the left of 1-byte region +// CHECK: allocated by thread T0 here: +// CHECK: {{#0 .* operator new }} +// CHECK: {{#1 .* main .*operator_new_left_oob.cc}}:[[@LINE-8]] + delete buffer; +} diff --git a/test/asan/TestCases/Windows/operator_new_right_oob.cc b/test/asan/TestCases/Windows/operator_new_right_oob.cc new file mode 100644 index 000000000000..7a66d1714b97 --- /dev/null +++ b/test/asan/TestCases/Windows/operator_new_right_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +int main() { + char *buffer = new char; + buffer[1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK: {{#0 .* main .*operator_new_right_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes to the right of 1-byte region +// CHECK: allocated by thread T0 here: +// CHECK: {{#0 .* operator new }} +// CHECK: {{#1 .* main .*operator_new_right_oob.cc}}:[[@LINE-8]] + delete buffer; +} diff --git a/test/asan/TestCases/Windows/operator_new_uaf.cc b/test/asan/TestCases/Windows/operator_new_uaf.cc new file mode 100644 index 000000000000..c435458f0c1c --- /dev/null +++ b/test/asan/TestCases/Windows/operator_new_uaf.cc @@ -0,0 +1,22 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +int main() { + char *buffer = new char; + delete buffer; + *buffer = 42; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK: {{#0 .* main .*operator_new_uaf.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes inside of 1-byte region +// CHECK-LABEL: freed by thread T0 here: +// CHECK: {{#0 .* operator delete }} +// CHECK: {{#1 .* main .*operator_new_uaf.cc}}:[[@LINE-8]] +// CHECK-LABEL: previously allocated by thread T0 here: +// CHECK: {{#0 .* operator new }} +// CHECK: {{#1 .* main .*operator_new_uaf.cc}}:[[@LINE-12]] + return 0; +} + diff --git a/test/asan/TestCases/Windows/realloc_left_oob.cc b/test/asan/TestCases/Windows/realloc_left_oob.cc new file mode 100644 index 000000000000..7d30e1d5c4ad --- /dev/null +++ b/test/asan/TestCases/Windows/realloc_left_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + char *buffer = (char*)realloc(0, 42); + buffer[-1] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*realloc_left_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region +// CHECK: allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* realloc }} +// CHECK-NEXT: {{#1 .* main .*realloc_left_oob.cc}}:[[@LINE-8]] + free(buffer); +} diff --git a/test/asan/TestCases/Windows/realloc_right_oob.cc b/test/asan/TestCases/Windows/realloc_right_oob.cc new file mode 100644 index 000000000000..f741390bd4e9 --- /dev/null +++ b/test/asan/TestCases/Windows/realloc_right_oob.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + char *buffer = (char*)realloc(0, 42); + buffer[42] = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*realloc_right_oob.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes to the right of 42-byte region +// CHECK: allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* realloc }} +// CHECK-NEXT: {{#1 .* main .*realloc_right_oob.cc}}:[[@LINE-8]] + free(buffer); +} diff --git a/test/asan/TestCases/Windows/realloc_uaf.cc b/test/asan/TestCases/Windows/realloc_uaf.cc new file mode 100644 index 000000000000..c5b6953cf76a --- /dev/null +++ b/test/asan/TestCases/Windows/realloc_uaf.cc @@ -0,0 +1,20 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + char *buffer = (char*)realloc(0, 42); + free(buffer); + buffer[0] = 42; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*realloc_uaf.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region +// CHECK: freed by thread T0 here: +// CHECK-NEXT: {{#0 .* free }} +// CHECK-NEXT: {{#1 .* main .*realloc_uaf.cc}}:[[@LINE-8]] +// CHECK: previously allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* realloc }} +// CHECK-NEXT: {{#1 .* main .*realloc_uaf.cc}}:[[@LINE-12]] +} diff --git a/test/asan/TestCases/Windows/report_after_syminitialize.cc b/test/asan/TestCases/Windows/report_after_syminitialize.cc new file mode 100644 index 000000000000..faf5e35db5f5 --- /dev/null +++ b/test/asan/TestCases/Windows/report_after_syminitialize.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include <windows.h> +#include <dbghelp.h> + +int main() { + // Make sure the RTL recovers from "no options enabled" dbghelp setup. + SymSetOptions(0); + + // Make sure the RTL recovers from "fInvadeProcess=FALSE". + if (!SymInitialize(GetCurrentProcess(), 0, FALSE)) + return 42; + + *(volatile int*)0 = 42; + // CHECK: ERROR: AddressSanitizer: access-violation on unknown address + // CHECK-NEXT: {{WARNING: .*DbgHelp}} + // CHECK: {{#0 0x.* in main.*report_after_syminitialize.cc:}}[[@LINE-3]] + // CHECK: AddressSanitizer can not provide additional info. +} diff --git a/test/asan/TestCases/Windows/seh.cc b/test/asan/TestCases/Windows/seh.cc new file mode 100644 index 000000000000..50cf6ddba8d6 --- /dev/null +++ b/test/asan/TestCases/Windows/seh.cc @@ -0,0 +1,56 @@ +// Clang doesn't support SEH on Windows yet, so for the time being we +// build this program in two parts: the code with SEH is built with CL, +// the rest is built with Clang. This represents the typical scenario when we +// build a large project using "clang-cl -fallback -fsanitize=address". +// +// Check both -GS and -GS- builds: +// RUN: cl -c %s -Fo%t.obj +// RUN: %clangxx_asan -o %t.exe %s %t.obj +// RUN: %run %t.exe +// +// RUN: cl -GS- -c %s -Fo%t.obj +// RUN: %clangxx_asan -o %t.exe %s %t.obj +// RUN: %run %t.exe + +#include <windows.h> +#include <assert.h> +#include <stdio.h> + +// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are +// supported and we don't need to use CL. +extern "C" bool __asan_address_is_poisoned(void *p); + +void ThrowAndCatch(); + +#if !defined(__clang__) +__declspec(noinline) +void Throw() { + int local, zero = 0; + fprintf(stderr, "Throw: %p\n", &local); + local = 5 / zero; +} + +__declspec(noinline) +void ThrowAndCatch() { + int local; + __try { + Throw(); + } __except(EXCEPTION_EXECUTE_HANDLER) { + fprintf(stderr, "__except: %p\n", &local); + } +} +#else + +int main() { + char x[32]; + fprintf(stderr, "Before: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + assert(__asan_address_is_poisoned(x + 32)); + ThrowAndCatch(); + fprintf(stderr, "After: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + // FIXME: Invert this assertion once we fix + // https://code.google.com/p/address-sanitizer/issues/detail?id=258 + assert(!__asan_address_is_poisoned(x + 32)); +} +#endif diff --git a/test/asan/TestCases/Windows/stack_array_left_oob.cc b/test/asan/TestCases/Windows/stack_array_left_oob.cc new file mode 100644 index 000000000000..040d855b48e2 --- /dev/null +++ b/test/asan/TestCases/Windows/stack_array_left_oob.cc @@ -0,0 +1,16 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> + +int main() { + int subscript = -1; + char buffer[42]; + buffer[subscript] = 42; +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}}:[[@LINE-3]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame +// CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}} +// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable +} diff --git a/test/asan/TestCases/Windows/stack_array_right_oob.cc b/test/asan/TestCases/Windows/stack_array_right_oob.cc new file mode 100644 index 000000000000..a370246aa072 --- /dev/null +++ b/test/asan/TestCases/Windows/stack_array_right_oob.cc @@ -0,0 +1,16 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> + +int main() { + int subscript = 42; + char buffer[42]; + buffer[subscript] = 42; +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}}:[[@LINE-3]] +// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame +// CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}} +// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] overflows this variable +} diff --git a/test/asan/TestCases/Windows/stack_array_sanity.cc b/test/asan/TestCases/Windows/stack_array_sanity.cc new file mode 100644 index 000000000000..1aef1a923d24 --- /dev/null +++ b/test/asan/TestCases/Windows/stack_array_sanity.cc @@ -0,0 +1,12 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t | FileCheck %s + +#include <stdio.h> + +int main() { + int subscript = 1; + char buffer[42]; + buffer[subscript] = 42; + printf("OK\n"); +// CHECK: OK +} diff --git a/test/asan/TestCases/Windows/stack_use_after_return.cc b/test/asan/TestCases/Windows/stack_use_after_return.cc new file mode 100644 index 000000000000..7955f2685308 --- /dev/null +++ b/test/asan/TestCases/Windows/stack_use_after_return.cc @@ -0,0 +1,22 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s + +char *x; + +void foo() { + char stack_buffer[42]; + x = &stack_buffer[13]; +} + +int main() { + foo(); + *x = 42; +// CHECK: AddressSanitizer: stack-use-after-return +// CHECK: WRITE of size 1 at {{.*}} thread T0 +// CHECK-NEXT: {{#0 0x.* in main .*stack_use_after_return.cc}}:[[@LINE-3]] +// +// CHECK: is located in stack of thread T0 at offset [[OFFSET:.*]] in frame +// CHECK-NEXT: {{#0 0x.* in foo .*stack_use_after_return.cc}} +// +// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable +} diff --git a/test/asan/TestCases/Windows/thread_simple.cc b/test/asan/TestCases/Windows/thread_simple.cc new file mode 100644 index 000000000000..14bb82f042aa --- /dev/null +++ b/test/asan/TestCases/Windows/thread_simple.cc @@ -0,0 +1,26 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +#include <windows.h> + +DWORD WINAPI thread_proc(void *) { + volatile char stack_buffer[42]; + for (int i = 0; i < sizeof(stack_buffer); ++i) + stack_buffer[i] = 42; + return 0x42; +} + +int main() { + DWORD exitcode; + HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL); + if (thr == 0) + return 1; + if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE)) + return 2; + + GetExitCodeThread(thr, &exitcode); + if (exitcode != 0x42) + return 3; + CloseHandle(thr); +} + diff --git a/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc new file mode 100644 index 000000000000..17b9b1bf8ecb --- /dev/null +++ b/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc @@ -0,0 +1,27 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +DWORD WINAPI thread_proc(void *) { + int subscript = -1; + volatile char stack_buffer[42]; + stack_buffer[subscript] = 42; +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T1 +// CHECK: {{#0 .* thread_proc .*thread_stack_array_left_oob.cc}}:[[@LINE-3]] +// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset {{.*}} in frame +// CHECK: thread_proc + return 0; +} + +int main() { + HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL); +// CHECK: Thread T1 created by T0 here: +// CHECK: {{#[01] .* main .*thread_stack_array_left_oob.cc}}:[[@LINE-2]] + + // A failure to create a thread should fail the test! + if (thr == 0) return 0; + + WaitForSingleObject(thr, INFINITE); +} diff --git a/test/asan/TestCases/Windows/thread_stack_array_right_oob.cc b/test/asan/TestCases/Windows/thread_stack_array_right_oob.cc new file mode 100644 index 000000000000..601a1b8a8760 --- /dev/null +++ b/test/asan/TestCases/Windows/thread_stack_array_right_oob.cc @@ -0,0 +1,27 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +DWORD WINAPI thread_proc(void *) { + int subscript = 42; + volatile char stack_buffer[42]; + stack_buffer[subscript] = 42; +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T1 +// CHECK: {{#0 .* thread_proc .*thread_stack_array_right_oob.cc}}:[[@LINE-3]] +// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset {{.*}} in frame +// CHECK: thread_proc + return 0; +} + +int main(void) { + HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL); +// CHECK: Thread T1 created by T0 here: +// CHECK: {{#[01] .* main .*thread_stack_array_right_oob.cc}}:[[@LINE-2]] + + // A failure to create a thread should fail the test! + if (thr == 0) return 0; + + WaitForSingleObject(thr, INFINITE); +} diff --git a/test/asan/TestCases/Windows/thread_stack_reuse.cc b/test/asan/TestCases/Windows/thread_stack_reuse.cc new file mode 100644 index 000000000000..7da3a807dac1 --- /dev/null +++ b/test/asan/TestCases/Windows/thread_stack_reuse.cc @@ -0,0 +1,37 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +#include <windows.h> + +DWORD WINAPI thread_proc_1(void *) { + volatile int x, y, z; + x = 1; + y = 2; + z = 3; + return 0; +} + +DWORD WINAPI thread_proc_2(void *) { + volatile char stack_buffer[42]; + for (int i = 0; i < sizeof(stack_buffer); ++i) + stack_buffer[i] = 42; + return 0; +} + +int main(void) { + HANDLE thr = NULL; + + thr = CreateThread(NULL, 0, thread_proc_1, NULL, 0, NULL); + if (thr == 0) + return 1; + if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE)) + return 2; + + thr = CreateThread(NULL, 0, thread_proc_2, NULL, 0, NULL); + if (thr == 0) + return 3; + if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE)) + return 4; + CloseHandle(thr); +} + diff --git a/test/asan/TestCases/Windows/thread_stress.cc b/test/asan/TestCases/Windows/thread_stress.cc new file mode 100644 index 000000000000..74be8d88c665 --- /dev/null +++ b/test/asan/TestCases/Windows/thread_stress.cc @@ -0,0 +1,30 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +#include <windows.h> + +DWORD WINAPI thread_proc(void *) { + volatile char stack_buffer[42]; + for (int i = 0; i < sizeof(stack_buffer); ++i) + stack_buffer[i] = 42; + return 0; +} + +int main(void) { + for (int iter = 0; iter < 1024; ++iter) { + const int NUM_THREADS = 8; + HANDLE thr[NUM_THREADS]; + for (int i = 0; i < NUM_THREADS; ++i) { + thr[i] = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL); + if (thr[i] == 0) + return 1; + } + for (int i = 0; i < NUM_THREADS; ++i) { + if (WAIT_OBJECT_0 != WaitForSingleObject(thr[i], INFINITE)) + return 2; + CloseHandle(thr[i]); + } + } + return 0; +} + diff --git a/test/asan/TestCases/Windows/throw_catch.cc b/test/asan/TestCases/Windows/throw_catch.cc new file mode 100644 index 000000000000..5313d25b26d6 --- /dev/null +++ b/test/asan/TestCases/Windows/throw_catch.cc @@ -0,0 +1,73 @@ +// Clang doesn't support exceptions on Windows yet, so for the time being we +// build this program in two parts: the code with exceptions is built with CL, +// the rest is built with Clang. This represents the typical scenario when we +// build a large project using "clang-cl -fallback -fsanitize=address". +// +// RUN: cl -c %s -Fo%t.obj +// RUN: %clangxx_asan -o %t.exe %s %t.obj +// RUN: %run %t.exe + +#include <assert.h> +#include <stdio.h> + +// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are +// supported and we don't need to use CL. +extern "C" bool __asan_address_is_poisoned(void *p); + +void ThrowAndCatch(); +void TestThrowInline(); + +#if !defined(__clang__) +__declspec(noinline) +void Throw() { + int local; + fprintf(stderr, "Throw: %p\n", &local); + throw 1; +} + +__declspec(noinline) +void ThrowAndCatch() { + int local; + try { + Throw(); + } catch(...) { + fprintf(stderr, "Catch: %p\n", &local); + } +} + +void TestThrowInline() { + char x[32]; + fprintf(stderr, "Before: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + try { + Throw(); + } catch(...) { + fprintf(stderr, "Catch\n"); + } + fprintf(stderr, "After: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + // FIXME: Invert this assertion once we fix + // https://code.google.com/p/address-sanitizer/issues/detail?id=258 + assert(!__asan_address_is_poisoned(x + 32)); +} + +#else + +void TestThrow() { + char x[32]; + fprintf(stderr, "Before: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + assert(__asan_address_is_poisoned(x + 32)); + ThrowAndCatch(); + fprintf(stderr, "After: %p poisoned: %d\n", &x, + __asan_address_is_poisoned(x + 32)); + // FIXME: Invert this assertion once we fix + // https://code.google.com/p/address-sanitizer/issues/detail?id=258 + assert(!__asan_address_is_poisoned(x + 32)); +} + +int main(int argc, char **argv) { + TestThrowInline(); + TestThrow(); +} +#endif diff --git a/test/asan/TestCases/Windows/use_after_realloc.cc b/test/asan/TestCases/Windows/use_after_realloc.cc new file mode 100644 index 000000000000..9d2c025258fa --- /dev/null +++ b/test/asan/TestCases/Windows/use_after_realloc.cc @@ -0,0 +1,23 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <malloc.h> + +int main() { + char *buffer = (char*)realloc(0, 32), + *stale = buffer; + buffer = (char*)realloc(buffer, 64); + // The 'stale' may now point to a free'd memory. + stale[0] = 42; +// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 .* main .*use_after_realloc.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes inside of 32-byte region +// CHECK: freed by thread T0 here: +// CHECK-NEXT: {{#0 .* realloc }} +// CHECK-NEXT: {{#1 .* main .*use_after_realloc.cc}}:[[@LINE-9]] +// CHECK: previously allocated by thread T0 here: +// CHECK-NEXT: {{#0 .* realloc }} +// CHECK-NEXT: {{#1 .* main .*use_after_realloc.cc}}:[[@LINE-14]] + free(buffer); +} diff --git a/test/asan/TestCases/Windows/use_after_return_linkage.cc b/test/asan/TestCases/Windows/use_after_return_linkage.cc new file mode 100644 index 000000000000..48c5065a0fa9 --- /dev/null +++ b/test/asan/TestCases/Windows/use_after_return_linkage.cc @@ -0,0 +1,12 @@ +// Make sure LIBCMT doesn't accidentally get added to the list of DEFAULTLIB +// directives. REQUIRES: asan-dynamic-runtime +// RUN: %clang_cl_asan -LD %s | FileCheck %s +// CHECK: Creating library +// CHECK-NOT: LIBCMT + +void foo(int *p) { *p = 42; } + +__declspec(dllexport) void bar() { + int x; + foo(&x); +} diff --git a/test/asan/TestCases/Windows/windows_h.cc b/test/asan/TestCases/Windows/windows_h.cc new file mode 100644 index 000000000000..40cf5a10ad4f --- /dev/null +++ b/test/asan/TestCases/Windows/windows_h.cc @@ -0,0 +1,7 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +// Just make sure we can parse <windows.h> +#include <windows.h> + +int main() {} diff --git a/test/asan/TestCases/Windows/wrong_downcast_on_heap.cc b/test/asan/TestCases/Windows/wrong_downcast_on_heap.cc new file mode 100644 index 000000000000..112dd5308d11 --- /dev/null +++ b/test/asan/TestCases/Windows/wrong_downcast_on_heap.cc @@ -0,0 +1,26 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +class Parent { + public: + int field; +}; + +class Child : public Parent { + public: + int extra_field; +}; + +int main(void) { + Parent *p = new Parent; + Child *c = (Child*)p; // Intentional error here! + c->extra_field = 42; +// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK: {{#0 0x[0-9a-f]* in main .*wrong_downcast_on_heap.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located 0 bytes to the right of 4-byte region +// CHECK: allocated by thread T0 here: +// CHECK: #0 {{.*}} operator new + return 0; +} + diff --git a/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc new file mode 100644 index 000000000000..2859ecc521d2 --- /dev/null +++ b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc @@ -0,0 +1,26 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +class Parent { + public: + int field; +}; + +class Child : public Parent { + public: + int extra_field; +}; + +int main(void) { + Parent p; + Child *c = (Child*)&p; // Intentional error here! + c->extra_field = 42; +// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: {{#0 0x[0-9a-f]* in main .*wrong_downcast_on_stack.cc}}:[[@LINE-3]] +// CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:[0-9]+]] in frame +// CHECK-NEXT: {{#0 0x[0-9a-f]* in main }} +// CHECK: 'p' <== Memory access at offset [[OFFSET]] overflows this variable + return 0; +} + |