summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMatthew G McGovern <matthew.mcgovern@microsoft.com>2019-07-08 19:58:50 +0000
committerMatthew G McGovern <matthew.mcgovern@microsoft.com>2019-07-08 19:58:50 +0000
commit3ef3d42864c06361ca05c26a9f9d05017c444844 (patch)
tree9e0f23a6baf65b393ddf64f5285ee8293412c65f /test
parent21d4d46951455ef43a407202ee4f24dd5b37cff4 (diff)
downloadcompiler-rt-3ef3d42864c06361ca05c26a9f9d05017c444844.tar.gz
[sanitizers][windows] Rtl-Heap Interception and tests
- Adds interceptors for Rtl[Allocate|Free|Size|ReAllocate]Heap - Adds unit tests for the new interceptors and expands HeapAlloc tests to demonstrate new functionality. Reviewed as D62927 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@365381 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r--test/asan/TestCases/Windows/dll_host.cc4
-rw-r--r--test/asan/TestCases/Windows/dll_unload.cc51
-rw-r--r--test/asan/TestCases/Windows/heapalloc.cc13
-rw-r--r--test/asan/TestCases/Windows/heapalloc_dll_double_free.cc40
-rw-r--r--test/asan/TestCases/Windows/heapalloc_dll_unload_realloc_uaf.cc40
-rw-r--r--test/asan/TestCases/Windows/heapalloc_doublefree.cc16
-rw-r--r--test/asan/TestCases/Windows/heapalloc_flags_fallback.cc20
-rw-r--r--test/asan/TestCases/Windows/heapalloc_huge.cc9
-rw-r--r--test/asan/TestCases/Windows/heapalloc_rtl_transfer.cc98
-rw-r--r--test/asan/TestCases/Windows/heapalloc_sanity.cc13
-rw-r--r--test/asan/TestCases/Windows/heapalloc_transfer.cc28
-rw-r--r--test/asan/TestCases/Windows/heapalloc_uaf.cc13
-rw-r--r--test/asan/TestCases/Windows/heapalloc_zero_size.cc23
-rw-r--r--test/asan/TestCases/Windows/heaprealloc.cc23
-rw-r--r--test/asan/TestCases/Windows/heaprealloc_alloc_zero.cc58
-rw-r--r--test/asan/TestCases/Windows/heaprealloc_zero_size.cc4
-rw-r--r--test/asan/TestCases/Windows/queue_user_work_item_report.cc6
-rw-r--r--test/asan/TestCases/Windows/rtlallocateheap.cc30
-rw-r--r--test/asan/TestCases/Windows/rtlallocateheap_dll_unload_double_free.cc72
-rw-r--r--test/asan/TestCases/Windows/rtlallocateheap_dll_unload_realloc.cc76
-rw-r--r--test/asan/TestCases/Windows/rtlallocateheap_flags_fallback.cc45
-rw-r--r--test/asan/TestCases/Windows/rtlallocateheap_zero.cc68
22 files changed, 746 insertions, 4 deletions
diff --git a/test/asan/TestCases/Windows/dll_host.cc b/test/asan/TestCases/Windows/dll_host.cc
index 512f930bc..9a4181541 100644
--- a/test/asan/TestCases/Windows/dll_host.cc
+++ b/test/asan/TestCases/Windows/dll_host.cc
@@ -32,6 +32,10 @@
// IMPORT: __asan_wrap_RaiseException
// IMPORT: __asan_wrap_RtlRaiseException
// IMPORT: __asan_wrap_SetUnhandledExceptionFilter
+// IMPORT: __asan_wrap_RtlSizeHeap
+// IMPORT: __asan_wrap_RtlAllocateHeap
+// IMPORT: __asan_wrap_RtlReAllocateHeap
+// IMPORT: __asan_wrap_RtlFreeHeap
//
// RUN: cat %t.imports1 %t.imports2 | sort | uniq > %t.imports-sorted
// RUN: cat %t.exports1 %t.exports2 | sort | uniq > %t.exports-sorted
diff --git a/test/asan/TestCases/Windows/dll_unload.cc b/test/asan/TestCases/Windows/dll_unload.cc
new file mode 100644
index 000000000..055567a0f
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_unload.cc
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <windows.h>
+
+// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
+// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
+// REQUIRES: asan-dynamic-runtime
+// REQUIRES: asan-32-bits
+
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+extern "C" {
+#if defined(EXE)
+
+int main(int argc, char **argv) {
+ void *region_without_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
+ HMODULE lib = LoadLibraryA(argv[1]);
+ assert(lib != INVALID_HANDLE_VALUE);
+
+ void *region_w_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
+ assert(region_w_hooks != nullptr);
+ assert(0 != FreeLibrary(lib));
+
+ fprintf(stderr, "WITHOUT:0x%08x\n", (unsigned int)region_without_hooks);
+ fprintf(stderr, "WITH:0x%08x\n", (unsigned int)region_w_hooks);
+
+ assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
+ assert(0 != HeapFree(GetProcessHeap(), 0, region_w_hooks));
+
+ HeapFree(GetProcessHeap(), 0, region_w_hooks); //will dump
+}
+#elif defined(DLL)
+// This global is registered at startup.
+
+BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
+ fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
+ fflush(0);
+ return TRUE;
+}
+
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+// CHECK: WITHOUT:[[WITHOUT:0x[0-9a-fA-F]+]]
+// CHECK: WITH:[[WITH:0x[0-9a-fA-F]+]]
+// CHECK: AddressSanitizer: attempting double-free on [[WITH]] in thread T0:
+
+#else
+#error oops!
+#endif
+}
diff --git a/test/asan/TestCases/Windows/heapalloc.cc b/test/asan/TestCases/Windows/heapalloc.cc
new file mode 100644
index 000000000..66322a3e7
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc.cc
@@ -0,0 +1,13 @@
+// XFAIL: asan-64-bits
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+int main() {
+ char *buffer;
+ buffer = (char *)HeapAlloc(GetProcessHeap(), 0, 32),
+ buffer[33] = 'a';
+ // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+ // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
diff --git a/test/asan/TestCases/Windows/heapalloc_dll_double_free.cc b/test/asan/TestCases/Windows/heapalloc_dll_double_free.cc
new file mode 100644
index 000000000..496289ae1
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_dll_double_free.cc
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <windows.h>
+
+// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
+// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
+// REQUIRES: asan-dynamic-runtime
+// REQUIRES: asan-32-bits
+
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+extern "C" {
+#if defined(EXE)
+
+int main(int argc, char **argv) {
+ void *region_without_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
+ HMODULE lib = LoadLibraryA(argv[1]);
+ assert(lib != INVALID_HANDLE_VALUE);
+ assert(0 != FreeLibrary(lib));
+ assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
+ assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
+}
+#elif defined(DLL)
+// This global is registered at startup.
+
+BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
+ fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
+ fflush(0);
+ return TRUE;
+}
+
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
+
+#else
+#error oops!
+#endif
+}
diff --git a/test/asan/TestCases/Windows/heapalloc_dll_unload_realloc_uaf.cc b/test/asan/TestCases/Windows/heapalloc_dll_unload_realloc_uaf.cc
new file mode 100644
index 000000000..79b30f4a9
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_dll_unload_realloc_uaf.cc
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <windows.h>
+
+// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
+// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
+// REQUIRES: asan-dynamic-runtime
+// REQUIRES: asan-32-bits
+
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+extern "C" {
+#if defined(EXE)
+
+int main(int argc, char **argv) {
+ void *region_without_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
+ HMODULE lib = LoadLibraryA(argv[1]);
+ assert(lib != INVALID_HANDLE_VALUE);
+ assert(0 != FreeLibrary(lib));
+ assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
+ HeapReAlloc(GetProcessHeap(), 0, region_without_hooks, 100); //should throw nested error
+}
+#elif defined(DLL)
+// This global is registered at startup.
+
+BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
+ fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
+ fflush(0);
+ return TRUE;
+}
+
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
+
+#else
+#error oops!
+#endif
+}
diff --git a/test/asan/TestCases/Windows/heapalloc_doublefree.cc b/test/asan/TestCases/Windows/heapalloc_doublefree.cc
new file mode 100644
index 000000000..dcdf98932
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_doublefree.cc
@@ -0,0 +1,16 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+#include <cassert>
+#include <windows.h>
+
+int main() {
+ void *allocation = HeapAlloc(GetProcessHeap(), 0, 10);
+ assert(allocation != 0);
+ assert(HeapFree(GetProcessHeap(), 0, allocation));
+ HeapFree(GetProcessHeap(), 0, allocation); //will dump
+ assert(0 && "HeapFree double free should produce an ASAN dump\n");
+ return 0;
+}
+
+// CHECK: AddressSanitizer: attempting double-free on [[addr:0x[0-9a-fA-F]+]] in thread T0: \ No newline at end of file
diff --git a/test/asan/TestCases/Windows/heapalloc_flags_fallback.cc b/test/asan/TestCases/Windows/heapalloc_flags_fallback.cc
new file mode 100644
index 000000000..eda94ac00
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_flags_fallback.cc
@@ -0,0 +1,20 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+#include <assert.h>
+#include <stdio.h>
+#include <windows.h>
+
+extern "C" int
+__sanitizer_get_ownership(const volatile void *p);
+
+int main() {
+ char *buffer;
+ buffer = (char *)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, 32);
+ buffer[0] = 'a';
+ assert(!__sanitizer_get_ownership(buffer));
+ HeapFree(GetProcessHeap(), 0, buffer);
+ puts("Okay");
+ // CHECK: Okay
+}
diff --git a/test/asan/TestCases/Windows/heapalloc_huge.cc b/test/asan/TestCases/Windows/heapalloc_huge.cc
new file mode 100644
index 000000000..ce1fd6562
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_huge.cc
@@ -0,0 +1,9 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %env_asan_opts=allocator_may_return_null=true %run %t
+// RUN: %env_asan_opts=allocator_may_return_null=true:windows_hook_rtl_allocators=true %run %t
+// XFAIL: asan-64-bits
+#include <windows.h>
+int main() {
+ void *nope = HeapAlloc(GetProcessHeap(), 0, ((size_t)0) - 1);
+ return (nope == nullptr) ? 0 : 1;
+} \ No newline at end of file
diff --git a/test/asan/TestCases/Windows/heapalloc_rtl_transfer.cc b/test/asan/TestCases/Windows/heapalloc_rtl_transfer.cc
new file mode 100644
index 000000000..b621270d7
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_rtl_transfer.cc
@@ -0,0 +1,98 @@
+#include "sanitizer\allocator_interface.h"
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+
+// RUN: %clang_cl_asan %s -o%t
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+
+using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
+using ReAllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID, SIZE_T);
+
+using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
+
+int main() {
+ HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
+ if (!NtDllHandle) {
+ puts("Couldn't load ntdll??");
+ return -1;
+ }
+
+ auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
+ if (RtlAllocateHeap_ptr == 0) {
+ puts("Couldn't find RtlAllocateHeap");
+ return -1;
+ }
+
+ auto RtlReAllocateHeap_ptr = (ReAllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
+ if (RtlReAllocateHeap_ptr == 0) {
+ puts("Couldn't find RtlReAllocateHeap");
+ return -1;
+ }
+
+ //owned by rtl
+ void *alloc = RtlAllocateHeap_ptr(GetProcessHeap(),
+ HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, 100);
+ assert(alloc);
+ for (int i = 0; i < 100; i++) {
+ assert(((char *)alloc)[i] == 0);
+ ((char *)alloc)[i] = '\xcc';
+ }
+
+ // still owned by rtl
+ alloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
+ HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, alloc, 500);
+ assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
+ for (int i = 0; i < 100; i++) {
+ assert(((char *)alloc)[i] == '\xcc');
+ }
+ for (int i = 100; i < 500; i++) {
+ assert(((char *)alloc)[i] == 0);
+ ((char *)alloc)[i] = '\xcc';
+ }
+
+ //convert to asan owned
+ void *realloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
+ HEAP_ZERO_MEMORY, alloc, 600);
+ alloc = nullptr;
+ assert(realloc && __sanitizer_get_ownership(realloc));
+
+ for (int i = 0; i < 500; i++) {
+ assert(((char *)realloc)[i] == '\xcc');
+ }
+ for (int i = 500; i < 600; i++) {
+ assert(((char *)realloc)[i] == 0);
+ ((char *)realloc)[i] = '\xcc';
+ }
+ realloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
+ HEAP_ZERO_MEMORY, realloc, 2048);
+ assert(realloc && __sanitizer_get_ownership(realloc));
+
+ for (int i = 0; i < 600; i++) {
+ assert(((char *)realloc)[i] == '\xcc');
+ }
+ for (int i = 600; i < 2048; i++) {
+ assert(((char *)realloc)[i] == 0);
+ ((char *)realloc)[i] = '\xcc';
+ }
+ //convert back to rtl owned;
+ alloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
+ HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, realloc, 100);
+ assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
+ for (int i = 0; i < 100; i++) {
+ assert(((char *)alloc)[i] == '\xcc');
+ ((char *)alloc)[i] = 0;
+ }
+
+ auto usable_size = HeapSize(GetProcessHeap(), 0, alloc);
+ for (int i = 100; i < usable_size; i++) {
+ assert(((char *)alloc)[i] == 0);
+ }
+
+ printf("Success\n");
+}
+
+// CHECK-NOT: Assertion failed:
+// CHECK-NOT: AddressSanitizer
+// CHECK: Success \ No newline at end of file
diff --git a/test/asan/TestCases/Windows/heapalloc_sanity.cc b/test/asan/TestCases/Windows/heapalloc_sanity.cc
new file mode 100644
index 000000000..5dfc14b72
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_sanity.cc
@@ -0,0 +1,13 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <windows.h>
+
+int main() {
+ char *buffer;
+ buffer = (char *)HeapAlloc(GetProcessHeap(), 0, 32),
+ buffer[0] = 'a';
+ HeapFree(GetProcessHeap(), 0, buffer);
+ puts("Okay");
+ // CHECK: Okay
+}
diff --git a/test/asan/TestCases/Windows/heapalloc_transfer.cc b/test/asan/TestCases/Windows/heapalloc_transfer.cc
new file mode 100644
index 000000000..b3b5746d6
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_transfer.cc
@@ -0,0 +1,28 @@
+#include "sanitizer\allocator_interface.h"
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+// RUN: %clang_cl_asan %s -o%t
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+
+int main() {
+ //owned by rtl
+ void *alloc = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, 100);
+ assert(alloc);
+ // still owned by rtl
+ alloc = HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, alloc, 100);
+ assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
+ //convert to asan owned
+ void *realloc = HeapReAlloc(GetProcessHeap(), 0, alloc, 500);
+ alloc = nullptr;
+ assert(realloc && __sanitizer_get_ownership(realloc));
+ //convert back to rtl owned;
+ alloc = HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, realloc, 100);
+ assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
+ printf("Success\n");
+}
+
+// CHECK-NOT: assert
+// CHECK-NOT: AddressSanitizer
+// CHECK: Success \ No newline at end of file
diff --git a/test/asan/TestCases/Windows/heapalloc_uaf.cc b/test/asan/TestCases/Windows/heapalloc_uaf.cc
new file mode 100644
index 000000000..00fb3ab6f
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_uaf.cc
@@ -0,0 +1,13 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+#include <windows.h>
+
+int main() {
+ char *buffer;
+ buffer = (char *)HeapAlloc(GetProcessHeap(), 0, 32),
+ HeapFree(GetProcessHeap(), 0, buffer);
+ buffer[0] = 'a';
+ // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+ // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
diff --git a/test/asan/TestCases/Windows/heapalloc_zero_size.cc b/test/asan/TestCases/Windows/heapalloc_zero_size.cc
new file mode 100644
index 000000000..23fc97b20
--- /dev/null
+++ b/test/asan/TestCases/Windows/heapalloc_zero_size.cc
@@ -0,0 +1,23 @@
+// RUN: %clang_cl_asan /Od -o %t %s
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=false %run %t 2>&1 | FileCheck %s
+// RUN: %clang_cl /Od -o %t %s
+// RUN: %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+
+int main() {
+ HANDLE heap = HeapCreate(0, 0, 0);
+ void *ptr = HeapAlloc(heap, 0, 4);
+ assert(ptr);
+ void *ptr2 = HeapReAlloc(heap, 0, ptr, 0);
+ assert(ptr2);
+ HeapFree(heap, 0, ptr2);
+ fprintf(stderr, "passed!\n");
+}
+
+// CHECK-NOT: double-free
+// CHECK-NOT: AddressSanitizer
+// CHECK: passed!
diff --git a/test/asan/TestCases/Windows/heaprealloc.cc b/test/asan/TestCases/Windows/heaprealloc.cc
new file mode 100644
index 000000000..e6efb87b5
--- /dev/null
+++ b/test/asan/TestCases/Windows/heaprealloc.cc
@@ -0,0 +1,23 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+#include <stdio.h>
+#include <windows.h>
+
+int main() {
+ char *oldbuf;
+ size_t sz = 8;
+ HANDLE procHeap = GetProcessHeap();
+ oldbuf = (char *)HeapAlloc(procHeap, 0, sz);
+ char *newbuf = oldbuf;
+ while (oldbuf == newbuf) {
+ sz *= 2;
+ newbuf = (char *)HeapReAlloc(procHeap, 0, oldbuf, sz);
+ }
+
+ newbuf[0] = 'a';
+ oldbuf[0] = 'a';
+ // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+ // CHECK: WRITE of size 1 at [[WRITE2:0x[0-9a-f]+]] thread T0
+ // CHECK: #0 {{0x[0-9a-f]+ in main.*}}:[[@LINE-3]]
+}
diff --git a/test/asan/TestCases/Windows/heaprealloc_alloc_zero.cc b/test/asan/TestCases/Windows/heaprealloc_alloc_zero.cc
new file mode 100644
index 000000000..76ae89690
--- /dev/null
+++ b/test/asan/TestCases/Windows/heaprealloc_alloc_zero.cc
@@ -0,0 +1,58 @@
+// RUN: %clang_cl_asan /Od /MT -o %t %s
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+#include <cassert>
+#include <iostream>
+#include <windows.h>
+
+int main() {
+ void *ptr = malloc(0);
+ if (ptr)
+ std::cerr << "allocated!\n";
+ ((char *)ptr)[0] = '\xff'; //check this 'allocate 1 instead of 0' hack hasn't changed
+
+ free(ptr);
+
+ /*
+ HeapAlloc hack for our asan interceptor is to change 0
+ sized allocations to size 1 to avoid weird inconsistencies
+ between how realloc and heaprealloc handle 0 size allocations.
+
+ Note this test relies on these instructions being intercepted.
+ Without ASAN HeapRealloc on line 27 would return a ptr whose
+ HeapSize would be 0. This test makes sure that the underlying behavior
+ of our hack hasn't changed underneath us.
+
+ We can get rid of the test (or change it to test for the correct
+ behavior) once we fix the interceptor or write a different allocator
+ to handle 0 sized allocations properly by default.
+
+ */
+ ptr = HeapAlloc(GetProcessHeap(), 0, 0);
+ if (!ptr)
+ return 1;
+ void *ptr2 = HeapReAlloc(GetProcessHeap(), 0, ptr, 0);
+ if (!ptr2)
+ return 1;
+ size_t heapsize = HeapSize(GetProcessHeap(), 0, ptr2);
+ if (heapsize != 1) { // will be 0 without ASAN turned on
+ std::cerr << "HeapAlloc size failure! " << heapsize << " != 1\n";
+ return 1;
+ }
+ void *ptr3 = HeapReAlloc(GetProcessHeap(), 0, ptr2, 3);
+ if (!ptr3)
+ return 1;
+ heapsize = HeapSize(GetProcessHeap(), 0, ptr3);
+
+ if (heapsize != 3) {
+ std::cerr << "HeapAlloc size failure! " << heapsize << " != 3\n";
+ return 1;
+ }
+ HeapFree(GetProcessHeap(), 0, ptr3);
+ return 0;
+}
+
+// CHECK: allocated!
+// CHECK-NOT: heap-buffer-overflow
+// CHECK-NOT: AddressSanitizer
+// CHECK-NOT: HeapAlloc size failure! \ No newline at end of file
diff --git a/test/asan/TestCases/Windows/heaprealloc_zero_size.cc b/test/asan/TestCases/Windows/heaprealloc_zero_size.cc
index 3d60202ce..ad2478b19 100644
--- a/test/asan/TestCases/Windows/heaprealloc_zero_size.cc
+++ b/test/asan/TestCases/Windows/heaprealloc_zero_size.cc
@@ -1,7 +1,9 @@
// RUN: %clang_cl_asan /Od -o %t %s
-// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=false %run %t 2>&1 | FileCheck %s
// RUN: %clang_cl /Od -o %t %s
// RUN: %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
#include <cassert>
#include <stdio.h>
#include<windows.h>
diff --git a/test/asan/TestCases/Windows/queue_user_work_item_report.cc b/test/asan/TestCases/Windows/queue_user_work_item_report.cc
index 26bd5e09d..27c438a56 100644
--- a/test/asan/TestCases/Windows/queue_user_work_item_report.cc
+++ b/test/asan/TestCases/Windows/queue_user_work_item_report.cc
@@ -9,9 +9,9 @@ DWORD CALLBACK work_item(LPVOID) {
int subscript = -1;
volatile char stack_buffer[42];
stack_buffer[subscript] = 42;
-// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T1
-// CHECK: {{#0 .* work_item.*queue_user_work_item_report.cc}}:[[@LINE-3]]
+ // CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]]
+ // CHECK: WRITE of size 1 at [[ADDR]] thread T{{[0-9]+}}
+ // CHECK: {{#0 .* work_item.*queue_user_work_item_report.cc}}:[[@LINE-3]]
SetEvent(done);
return 0;
}
diff --git a/test/asan/TestCases/Windows/rtlallocateheap.cc b/test/asan/TestCases/Windows/rtlallocateheap.cc
new file mode 100644
index 000000000..5831fe27b
--- /dev/null
+++ b/test/asan/TestCases/Windows/rtlallocateheap.cc
@@ -0,0 +1,30 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t /MD
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+// REQUIRES: asan-rtl-heap-interception
+
+#include <stdio.h>
+#include <windows.h>
+
+using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
+using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
+
+int main() {
+ HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
+ if (!NtDllHandle) {
+ puts("Couldn't load ntdll??");
+ return -1;
+ }
+
+ auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
+ if (RtlAllocateHeap_ptr == 0) {
+ puts("Couldn't RtlAllocateHeap");
+ return -1;
+ }
+
+ char *buffer;
+ buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32),
+ buffer[33] = 'a';
+ // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+ // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
diff --git a/test/asan/TestCases/Windows/rtlallocateheap_dll_unload_double_free.cc b/test/asan/TestCases/Windows/rtlallocateheap_dll_unload_double_free.cc
new file mode 100644
index 000000000..078114506
--- /dev/null
+++ b/test/asan/TestCases/Windows/rtlallocateheap_dll_unload_double_free.cc
@@ -0,0 +1,72 @@
+// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
+// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
+// REQUIRES: asan-dynamic-runtime
+// REQUIRES: asan-32-bits
+// REQUIRES: asan-rtl-heap-interception
+
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+
+extern "C" {
+#if defined(EXE)
+using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
+using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
+
+int main(int argc, char **argv) {
+ HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
+ if (!NtDllHandle) {
+ puts("Couldn't load ntdll??");
+ return -1;
+ }
+
+ auto RtlAllocateHeap_ptr =
+ (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
+ if (RtlAllocateHeap_ptr == 0) {
+ puts("Couldn't RtlAllocateHeap");
+ return -1;
+ }
+
+ auto RtlFreeHeap_ptr =
+ (FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
+ if (RtlFreeHeap_ptr == 0) {
+ puts("Couldn't get RtlFreeHeap");
+ return -1;
+ }
+
+ char *buffer;
+ buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32);
+
+ HMODULE lib = LoadLibraryA(argv[1]);
+ assert(lib != INVALID_HANDLE_VALUE);
+ assert(0 != FreeLibrary(lib));
+
+ if (!RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer)) {
+ puts("Couldn't RtlFreeHeap");
+ return -1;
+ }
+ // Because this pointer was allocated pre-hooking,
+ // this will dump as a nested bug. Asan attempts to free
+ // the pointer and AV's, so the ASAN exception handler
+ // will dump as a 'nested bug'.
+ RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer);
+}
+
+#elif defined(DLL)
+// This global is registered at startup.
+
+BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
+ fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
+ fflush(0);
+ return TRUE;
+}
+
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
+
+#else
+#error oops!
+#endif
+}
diff --git a/test/asan/TestCases/Windows/rtlallocateheap_dll_unload_realloc.cc b/test/asan/TestCases/Windows/rtlallocateheap_dll_unload_realloc.cc
new file mode 100644
index 000000000..a2758cad2
--- /dev/null
+++ b/test/asan/TestCases/Windows/rtlallocateheap_dll_unload_realloc.cc
@@ -0,0 +1,76 @@
+// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
+// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
+// REQUIRES: asan-dynamic-runtime
+// REQUIRES: asan-32-bits
+// REQUIRES: asan-rtl-heap-interception
+
+#include <cassert>
+#include <stdio.h>
+#include <windows.h>
+
+extern "C" {
+#if defined(EXE)
+using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
+using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
+using RtlReAllocateHeapPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID, SIZE_T);
+
+int main(int argc, char **argv) {
+ HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
+ if (!NtDllHandle) {
+ puts("Couldn't load ntdll??");
+ return -1;
+ }
+
+ auto RtlAllocateHeap_ptr =
+ (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
+ if (RtlAllocateHeap_ptr == 0) {
+ puts("Couldn't RtlAllocateHeap");
+ return -1;
+ }
+
+ auto RtlFreeHeap_ptr =
+ (FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
+ if (RtlFreeHeap_ptr == 0) {
+ puts("Couldn't get RtlFreeHeap");
+ return -1;
+ }
+
+ auto RtlReAllocateHeap_ptr =
+ (RtlReAllocateHeapPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
+ if (RtlReAllocateHeap_ptr == 0) {
+ puts("Couldn't get rtlreallocateheap\n");
+ return -1;
+ }
+
+ char *buffer;
+ buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32);
+
+ HMODULE lib = LoadLibraryA(argv[1]);
+ assert(lib != INVALID_HANDLE_VALUE);
+ assert(0 != FreeLibrary(lib));
+
+ if (!RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer)) {
+ puts("Couldn't RtlFreeHeap");
+ return -1;
+ }
+ RtlReAllocateHeap_ptr(GetProcessHeap(), 0, buffer, 100); // should dump
+}
+
+#elif defined(DLL)
+// This global is registered at startup.
+
+BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
+ fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
+ fflush(0);
+ return TRUE;
+}
+
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
+
+#else
+#error oops!
+#endif
+}
diff --git a/test/asan/TestCases/Windows/rtlallocateheap_flags_fallback.cc b/test/asan/TestCases/Windows/rtlallocateheap_flags_fallback.cc
new file mode 100644
index 000000000..c377fe360
--- /dev/null
+++ b/test/asan/TestCases/Windows/rtlallocateheap_flags_fallback.cc
@@ -0,0 +1,45 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t /MD
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+// REQUIRES: asan-rtl-heap-interception
+
+#include <assert.h>
+#include <stdio.h>
+#include <windows.h>
+
+extern "C" int __sanitizer_get_ownership(const volatile void *p);
+using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
+using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
+
+int main() {
+ HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
+ if (!NtDllHandle) {
+ puts("Couldn't load ntdll??");
+ return -1;
+ }
+
+ auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
+ if (RtlAllocateHeap_ptr == 0) {
+ puts("Couldn't RtlAllocateHeap");
+ return -1;
+ }
+
+ auto RtlFreeHeap_ptr = (FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
+ if (RtlFreeHeap_ptr == 0) {
+ puts("Couldn't RtlFreeHeap");
+ return -1;
+ }
+
+ char *winbuf;
+ char *asanbuf;
+ winbuf = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, 32),
+ asanbuf = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32),
+ winbuf[0] = 'a';
+ assert(!__sanitizer_get_ownership(winbuf));
+ assert(__sanitizer_get_ownership(asanbuf));
+
+ RtlFreeHeap_ptr(GetProcessHeap(), 0, winbuf);
+ RtlFreeHeap_ptr(GetProcessHeap(), 0, asanbuf);
+ puts("Okay");
+ // CHECK: Okay
+}
diff --git a/test/asan/TestCases/Windows/rtlallocateheap_zero.cc b/test/asan/TestCases/Windows/rtlallocateheap_zero.cc
new file mode 100644
index 000000000..d4bde7857
--- /dev/null
+++ b/test/asan/TestCases/Windows/rtlallocateheap_zero.cc
@@ -0,0 +1,68 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t /MD
+// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
+// XFAIL: asan-64-bits
+// REQUIRES: asan-rtl-heap-interception
+
+#include <assert.h>
+#include <stdio.h>
+#include <windows.h>
+
+using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
+using ReAllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID, SIZE_T);
+using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
+
+int main() {
+ HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
+ if (!NtDllHandle) {
+ puts("Couldn't load ntdll??");
+ return -1;
+ }
+
+ auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
+ if (RtlAllocateHeap_ptr == 0) {
+ puts("Couldn't find RtlAllocateHeap");
+ return -1;
+ }
+
+ auto RtlReAllocateHeap_ptr = (ReAllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
+ if (RtlReAllocateHeap_ptr == 0) {
+ puts("Couldn't find RtlReAllocateHeap");
+ return -1;
+ }
+
+ char *buffer;
+ SIZE_T buffer_size = 32;
+ SIZE_T new_buffer_size = buffer_size * 2;
+
+ buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size);
+ assert(buffer != nullptr);
+ // Check that the buffer is zeroed.
+ for (SIZE_T i = 0; i < buffer_size; ++i) {
+ assert(buffer[i] == 0);
+ }
+ memset(buffer, 0xcc, buffer_size);
+
+ // Zero the newly allocated memory.
+ buffer = (char *)RtlReAllocateHeap_ptr(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, new_buffer_size);
+ assert(buffer != nullptr);
+ // Check that the first part of the buffer still has the old contents.
+ for (SIZE_T i = 0; i < buffer_size; ++i) {
+ assert(buffer[i] == (char)0xcc);
+ }
+ // Check that the new part of the buffer is zeroed.
+ for (SIZE_T i = buffer_size; i < new_buffer_size; ++i) {
+ assert(buffer[i] == 0x0);
+ }
+
+ // Shrink the buffer back down.
+ buffer = (char *)RtlReAllocateHeap_ptr(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, buffer_size);
+ assert(buffer != nullptr);
+ // Check that the first part of the buffer still has the old contents.
+ for (SIZE_T i = 0; i < buffer_size; ++i) {
+ assert(buffer[i] == (char)0xcc);
+ }
+
+ buffer[buffer_size + 1] = 'a';
+ // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+ // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}