diff options
author | Matthew G McGovern <matthew.mcgovern@microsoft.com> | 2019-07-08 19:58:50 +0000 |
---|---|---|
committer | Matthew G McGovern <matthew.mcgovern@microsoft.com> | 2019-07-08 19:58:50 +0000 |
commit | 3ef3d42864c06361ca05c26a9f9d05017c444844 (patch) | |
tree | 9e0f23a6baf65b393ddf64f5285ee8293412c65f /test | |
parent | 21d4d46951455ef43a407202ee4f24dd5b37cff4 (diff) | |
download | compiler-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')
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 +} |