xref: /llvm-project/compiler-rt/test/asan/TestCases/Windows/rtlallocateheap_dll_unload_double_free.cpp (revision 51015af773775160c22df9a8252d34270f2698a2)
1 // RUN: %clang_cl_asan %LD %Od -DDLL %s %Fe%t.dll
2 // RUN: %clang_cl %Od -DEXE %s %Fe%te.exe
3 // RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
4 // REQUIRES: asan-dynamic-runtime
5 // REQUIRES: asan-32-bits
6 
7 #include <cassert>
8 #include <stdio.h>
9 #include <windows.h>
10 
11 extern "C" {
12 #if defined(EXE)
13 using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
14 using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
15 
main(int argc,char ** argv)16 int main(int argc, char **argv) {
17   HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
18   if (!NtDllHandle) {
19     puts("Couldn't load ntdll??");
20     return -1;
21   }
22 
23   auto RtlAllocateHeap_ptr =
24       (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
25   if (RtlAllocateHeap_ptr == 0) {
26     puts("Couldn't RtlAllocateHeap");
27     return -1;
28   }
29 
30   auto RtlFreeHeap_ptr =
31       (FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
32   if (RtlFreeHeap_ptr == 0) {
33     puts("Couldn't get RtlFreeHeap");
34     return -1;
35   }
36 
37   char *buffer;
38   buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32);
39 
40   HMODULE lib = LoadLibraryA(argv[1]);
41   assert(lib != INVALID_HANDLE_VALUE);
42   assert(0 != FreeLibrary(lib));
43 
44   if (!RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer)) {
45     puts("Couldn't RtlFreeHeap");
46     return -1;
47   }
48   // Because this pointer was allocated pre-hooking,
49   // this will dump as a nested bug. Asan attempts to free
50   // the pointer and AV's, so the ASAN exception handler
51   // will dump as a 'nested bug'.
52   RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer);
53 }
54 
55 #elif defined(DLL)
56 // This global is registered at startup.
57 
58 BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
59   fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
60   fflush(0);
61   return TRUE;
62 }
63 
64 // CHECK: in DLL(reason=1)
65 // CHECK: in DLL(reason=0)
66 // CHECK: AddressSanitizer: nested bug in the same thread, aborting.
67 
68 #else
69 #error oops!
70 #endif
71 }
72