aboutsummaryrefslogtreecommitdiff
path: root/test/asan/TestCases/Windows
diff options
context:
space:
mode:
Diffstat (limited to 'test/asan/TestCases/Windows')
-rw-r--r--test/asan/TestCases/Windows/aligned_mallocs.cc29
-rw-r--r--test/asan/TestCases/Windows/allocators_sanity.cc37
-rw-r--r--test/asan/TestCases/Windows/beginthreadex.cc21
-rw-r--r--test/asan/TestCases/Windows/bitfield.cc21
-rw-r--r--test/asan/TestCases/Windows/bitfield_uaf.cc34
-rw-r--r--test/asan/TestCases/Windows/calloc_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/calloc_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/calloc_uaf.cc20
-rw-r--r--test/asan/TestCases/Windows/crt_initializers.cc31
-rw-r--r--test/asan/TestCases/Windows/demangled_names.cc50
-rw-r--r--test/asan/TestCases/Windows/dll_aligned_mallocs.cc34
-rw-r--r--test/asan/TestCases/Windows/dll_allocators_sanity.cc39
-rw-r--r--test/asan/TestCases/Windows/dll_and_lib.cc19
-rw-r--r--test/asan/TestCases/Windows/dll_cerr.cc23
-rw-r--r--test/asan/TestCases/Windows/dll_host.cc49
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memchr.cc21
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memcpy.cc32
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc34
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memset.cc32
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_strlen.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_large_function.cc12
-rw-r--r--test/asan/TestCases/Windows/dll_malloc_left_oob.cc23
-rw-r--r--test/asan/TestCases/Windows/dll_malloc_uaf.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_noreturn.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_null_deref.cc18
-rw-r--r--test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc25
-rw-r--r--test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc33
-rw-r--r--test/asan/TestCases/Windows/dll_poison_unpoison.cc35
-rw-r--r--test/asan/TestCases/Windows/dll_seh.cc60
-rw-r--r--test/asan/TestCases/Windows/dll_stack_use_after_return.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc36
-rw-r--r--test/asan/TestCases/Windows/double_free.cc21
-rw-r--r--test/asan/TestCases/Windows/double_operator_delete.cc25
-rw-r--r--test/asan/TestCases/Windows/global_const_string.cc12
-rw-r--r--test/asan/TestCases/Windows/global_const_string_oob.cc20
-rw-r--r--test/asan/TestCases/Windows/hello_world.cc9
-rw-r--r--test/asan/TestCases/Windows/intercept_memcpy.cc31
-rw-r--r--test/asan/TestCases/Windows/intercept_strdup.cc27
-rw-r--r--test/asan/TestCases/Windows/intercept_strlen.cc27
-rw-r--r--test/asan/TestCases/Windows/lit.local.cfg14
-rw-r--r--test/asan/TestCases/Windows/longjmp.cc26
-rw-r--r--test/asan/TestCases/Windows/malloc_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/malloc_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/malloc_uaf.cc20
-rw-r--r--test/asan/TestCases/Windows/null_deref.cc15
-rw-r--r--test/asan/TestCases/Windows/null_deref_multiple_dlls.cc40
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_right_oob.cc18
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_uaf.cc24
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc25
-rw-r--r--test/asan/TestCases/Windows/operator_delete_wrong_argument.cc12
-rw-r--r--test/asan/TestCases/Windows/operator_new_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/operator_new_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/operator_new_uaf.cc22
-rw-r--r--test/asan/TestCases/Windows/realloc_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/realloc_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/realloc_uaf.cc20
-rw-r--r--test/asan/TestCases/Windows/report_after_syminitialize.cc19
-rw-r--r--test/asan/TestCases/Windows/seh.cc56
-rw-r--r--test/asan/TestCases/Windows/stack_array_left_oob.cc16
-rw-r--r--test/asan/TestCases/Windows/stack_array_right_oob.cc16
-rw-r--r--test/asan/TestCases/Windows/stack_array_sanity.cc12
-rw-r--r--test/asan/TestCases/Windows/stack_use_after_return.cc22
-rw-r--r--test/asan/TestCases/Windows/thread_simple.cc26
-rw-r--r--test/asan/TestCases/Windows/thread_stack_array_left_oob.cc27
-rw-r--r--test/asan/TestCases/Windows/thread_stack_array_right_oob.cc27
-rw-r--r--test/asan/TestCases/Windows/thread_stack_reuse.cc37
-rw-r--r--test/asan/TestCases/Windows/thread_stress.cc30
-rw-r--r--test/asan/TestCases/Windows/throw_catch.cc73
-rw-r--r--test/asan/TestCases/Windows/use_after_realloc.cc23
-rw-r--r--test/asan/TestCases/Windows/use_after_return_linkage.cc12
-rw-r--r--test/asan/TestCases/Windows/windows_h.cc7
-rw-r--r--test/asan/TestCases/Windows/wrong_downcast_on_heap.cc26
-rw-r--r--test/asan/TestCases/Windows/wrong_downcast_on_stack.cc26
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;
+}
+