Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 848a19e

Browse files
committedJul 9, 2019
[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 llvm-svn: 365422
1 parent 53d5f3a commit 848a19e

25 files changed

+1081
-55
lines changed
 

‎compiler-rt/lib/asan/asan_flags.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,5 @@ ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true,
158158
ASAN_FLAG(bool, verify_asan_link_order, true,
159159
"Check position of ASan runtime in library list (needs to be disabled"
160160
" when other library has to be preloaded system-wide)")
161+
ASAN_FLAG(bool, windows_hook_rtl_allocators, false,
162+
"(Windows only) enable hooking of Rtl(Allocate|Free|Size|ReAllocate)Heap.")

‎compiler-rt/lib/asan/asan_malloc_win.cc

Lines changed: 283 additions & 26 deletions
Large diffs are not rendered by default.

‎compiler-rt/lib/asan/asan_win.cc

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020

2121
#include "asan_interceptors.h"
2222
#include "asan_internal.h"
23+
#include "asan_mapping.h"
2324
#include "asan_report.h"
2425
#include "asan_stack.h"
2526
#include "asan_thread.h"
26-
#include "asan_mapping.h"
2727
#include "sanitizer_common/sanitizer_libc.h"
2828
#include "sanitizer_common/sanitizer_mutex.h"
2929
#include "sanitizer_common/sanitizer_win.h"
@@ -77,7 +77,7 @@ static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
7777
}
7878

7979
INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter,
80-
LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) {
80+
LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) {
8181
CHECK(REAL(SetUnhandledExceptionFilter));
8282
if (ExceptionFilter == &SEHHandler)
8383
return REAL(SetUnhandledExceptionFilter)(ExceptionFilter);
@@ -132,7 +132,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
132132
#endif
133133

134134
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
135-
AsanThread *t = (AsanThread*)arg;
135+
AsanThread *t = (AsanThread *)arg;
136136
SetCurrentThread(t);
137137
return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
138138
}
@@ -162,10 +162,9 @@ void InitializePlatformInterceptors() {
162162
// The interceptors were not designed to be removable, so we have to keep this
163163
// module alive for the life of the process.
164164
HMODULE pinned;
165-
CHECK(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
166-
GET_MODULE_HANDLE_EX_FLAG_PIN,
167-
(LPCWSTR)&InitializePlatformInterceptors,
168-
&pinned));
165+
CHECK(GetModuleHandleExW(
166+
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
167+
(LPCWSTR)&InitializePlatformInterceptors, &pinned));
169168

170169
ASAN_INTERCEPT_FUNC(CreateThread);
171170
ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
@@ -197,24 +196,46 @@ static bool tsd_key_inited = false;
197196

198197
static __declspec(thread) void *fake_tsd = 0;
199198

199+
// https://docs.microsoft.com/en-us/windows/desktop/api/winternl/ns-winternl-_teb
200+
// "[This structure may be altered in future versions of Windows. Applications
201+
// should use the alternate functions listed in this topic.]"
202+
typedef struct _TEB {
203+
PVOID Reserved1[12];
204+
// PVOID ThreadLocalStoragePointer; is here, at the last field in Reserved1.
205+
PVOID ProcessEnvironmentBlock;
206+
PVOID Reserved2[399];
207+
BYTE Reserved3[1952];
208+
PVOID TlsSlots[64];
209+
BYTE Reserved4[8];
210+
PVOID Reserved5[26];
211+
PVOID ReservedForOle;
212+
PVOID Reserved6[4];
213+
PVOID TlsExpansionSlots;
214+
} TEB, *PTEB;
215+
216+
constexpr size_t TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET = 11;
217+
BOOL IsTlsInitialized() {
218+
PTEB teb = (PTEB)NtCurrentTeb();
219+
return teb->Reserved1[TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET] !=
220+
nullptr;
221+
}
222+
200223
void AsanTSDInit(void (*destructor)(void *tsd)) {
201224
// FIXME: we're ignoring the destructor for now.
202225
tsd_key_inited = true;
203226
}
204227

205228
void *AsanTSDGet() {
206229
CHECK(tsd_key_inited);
207-
return fake_tsd;
230+
return IsTlsInitialized() ? fake_tsd : nullptr;
208231
}
209232

210233
void AsanTSDSet(void *tsd) {
211234
CHECK(tsd_key_inited);
212235
fake_tsd = tsd;
213236
}
214237

215-
void PlatformTSDDtor(void *tsd) {
216-
AsanThread::TSDDtor(tsd);
217-
}
238+
void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); }
218239
// }}}
219240

220241
// ---------------------- Various stuff ---------------- {{{
@@ -245,9 +266,7 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
245266
UNIMPLEMENTED();
246267
}
247268

248-
void AsanOnDeadlySignal(int, void *siginfo, void *context) {
249-
UNIMPLEMENTED();
250-
}
269+
void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); }
251270

252271
#if SANITIZER_WINDOWS64
253272
// Exception handler for dealing with shadow memory.
@@ -256,7 +275,9 @@ ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {
256275
uptr page_size = GetPageSizeCached();
257276
// Only handle access violations.
258277
if (exception_pointers->ExceptionRecord->ExceptionCode !=
259-
EXCEPTION_ACCESS_VIOLATION) {
278+
EXCEPTION_ACCESS_VIOLATION ||
279+
exception_pointers->ExceptionRecord->NumberParameters < 2) {
280+
__asan_handle_no_return();
260281
return EXCEPTION_CONTINUE_SEARCH;
261282
}
262283

@@ -265,7 +286,10 @@ ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {
265286
(uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]);
266287

267288
// Check valid shadow range.
268-
if (!AddrIsInShadow(addr)) return EXCEPTION_CONTINUE_SEARCH;
289+
if (!AddrIsInShadow(addr)) {
290+
__asan_handle_no_return();
291+
return EXCEPTION_CONTINUE_SEARCH;
292+
}
269293

270294
// This is an access violation while trying to read from the shadow. Commit
271295
// the relevant page and let execution continue.
@@ -276,7 +300,8 @@ ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {
276300
// Commit the page.
277301
uptr result =
278302
(uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE);
279-
if (result != page) return EXCEPTION_CONTINUE_SEARCH;
303+
if (result != page)
304+
return EXCEPTION_CONTINUE_SEARCH;
280305

281306
// The page mapping succeeded, so continue execution as usual.
282307
return EXCEPTION_CONTINUE_EXECUTION;
@@ -293,7 +318,7 @@ void InitializePlatformExceptionHandlers() {
293318
}
294319

295320
bool IsSystemHeapAddress(uptr addr) {
296-
return ::HeapValidate(GetProcessHeap(), 0, (void*)addr) != FALSE;
321+
return ::HeapValidate(GetProcessHeap(), 0, (void *)addr) != FALSE;
297322
}
298323

299324
// We want to install our own exception handler (EH) to print helpful reports
@@ -312,8 +337,7 @@ bool IsSystemHeapAddress(uptr addr) {
312337
// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
313338
// will be called for each instrumented module. This ensures that at least one
314339
// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
315-
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
316-
int __asan_set_seh_filter() {
340+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_seh_filter() {
317341
// We should only store the previous handler if it's not our own handler in
318342
// order to avoid loops in the EH chain.
319343
auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
@@ -347,12 +371,13 @@ __declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() =
347371
// which run before the CRT. Users also add code to .CRT$XLC, so it's important
348372
// to run our initializers first.
349373
static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) {
350-
if (reason == DLL_PROCESS_ATTACH) __asan_init();
374+
if (reason == DLL_PROCESS_ATTACH)
375+
__asan_init();
351376
}
352377

353378
#pragma section(".CRT$XLAB", long, read) // NOLINT
354-
__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
355-
unsigned long, void *) = asan_thread_init;
379+
__declspec(allocate(".CRT$XLAB")) void(NTAPI *__asan_tls_init)(
380+
void *, unsigned long, void *) = asan_thread_init;
356381
#endif
357382

358383
static void NTAPI asan_thread_exit(void *module, DWORD reason, void *reserved) {
@@ -365,8 +390,8 @@ static void NTAPI asan_thread_exit(void *module, DWORD reason, void *reserved) {
365390
}
366391

367392
#pragma section(".CRT$XLY", long, read) // NOLINT
368-
__declspec(allocate(".CRT$XLY")) void (NTAPI *__asan_tls_exit)(void *,
369-
unsigned long, void *) = asan_thread_exit;
393+
__declspec(allocate(".CRT$XLY")) void(NTAPI *__asan_tls_exit)(
394+
void *, unsigned long, void *) = asan_thread_exit;
370395

371396
WIN_FORCE_LINK(__asan_dso_reg_hook)
372397

‎compiler-rt/test/asan/TestCases/Windows/dll_host.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
// IMPORT: __asan_wrap_RaiseException
3333
// IMPORT: __asan_wrap_RtlRaiseException
3434
// IMPORT: __asan_wrap_SetUnhandledExceptionFilter
35+
// IMPORT: __asan_wrap_RtlSizeHeap
36+
// IMPORT: __asan_wrap_RtlAllocateHeap
37+
// IMPORT: __asan_wrap_RtlReAllocateHeap
38+
// IMPORT: __asan_wrap_RtlFreeHeap
3539
//
3640
// RUN: cat %t.imports1 %t.imports2 | sort | uniq > %t.imports-sorted
3741
// RUN: cat %t.exports1 %t.exports2 | sort | uniq > %t.exports-sorted
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <stdio.h>
2+
#include <windows.h>
3+
4+
// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
5+
// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
6+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
7+
// REQUIRES: asan-dynamic-runtime
8+
// REQUIRES: asan-32-bits
9+
10+
#include <cassert>
11+
#include <stdio.h>
12+
#include <windows.h>
13+
extern "C" {
14+
#if defined(EXE)
15+
16+
int main(int argc, char **argv) {
17+
void *region_without_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
18+
HMODULE lib = LoadLibraryA(argv[1]);
19+
assert(lib != INVALID_HANDLE_VALUE);
20+
21+
void *region_w_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
22+
assert(region_w_hooks != nullptr);
23+
assert(0 != FreeLibrary(lib));
24+
25+
fprintf(stderr, "WITHOUT:0x%08x\n", (unsigned int)region_without_hooks);
26+
fprintf(stderr, "WITH:0x%08x\n", (unsigned int)region_w_hooks);
27+
28+
assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
29+
assert(0 != HeapFree(GetProcessHeap(), 0, region_w_hooks));
30+
31+
HeapFree(GetProcessHeap(), 0, region_w_hooks); //will dump
32+
}
33+
#elif defined(DLL)
34+
// This global is registered at startup.
35+
36+
BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
37+
fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
38+
fflush(0);
39+
return TRUE;
40+
}
41+
42+
// CHECK: in DLL(reason=1)
43+
// CHECK: in DLL(reason=0)
44+
// CHECK: WITHOUT:[[WITHOUT:0x[0-9a-fA-F]+]]
45+
// CHECK: WITH:[[WITH:0x[0-9a-fA-F]+]]
46+
// CHECK: AddressSanitizer: attempting double-free on [[WITH]] in thread T0:
47+
48+
#else
49+
#error oops!
50+
#endif
51+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// XFAIL: asan-64-bits
2+
// RUN: %clang_cl_asan -O0 %s -Fe%t
3+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
4+
5+
#include <windows.h>
6+
7+
int main() {
8+
char *buffer;
9+
buffer = (char *)HeapAlloc(GetProcessHeap(), 0, 32),
10+
buffer[33] = 'a';
11+
// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
12+
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
13+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <stdio.h>
2+
#include <windows.h>
3+
4+
// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
5+
// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
6+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
7+
// REQUIRES: asan-dynamic-runtime
8+
// REQUIRES: asan-32-bits
9+
10+
#include <cassert>
11+
#include <stdio.h>
12+
#include <windows.h>
13+
extern "C" {
14+
#if defined(EXE)
15+
16+
int main(int argc, char **argv) {
17+
void *region_without_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
18+
HMODULE lib = LoadLibraryA(argv[1]);
19+
assert(lib != INVALID_HANDLE_VALUE);
20+
assert(0 != FreeLibrary(lib));
21+
assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
22+
assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
23+
}
24+
#elif defined(DLL)
25+
// This global is registered at startup.
26+
27+
BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
28+
fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
29+
fflush(0);
30+
return TRUE;
31+
}
32+
33+
// CHECK: in DLL(reason=1)
34+
// CHECK: in DLL(reason=0)
35+
// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
36+
37+
#else
38+
#error oops!
39+
#endif
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <stdio.h>
2+
#include <windows.h>
3+
4+
// RUN: %clang_cl_asan -LD /Od -DDLL %s -Fe%t.dll
5+
// RUN: %clang_cl /Od -DEXE %s -Fe%te.exe
6+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %te.exe %t.dll 2>&1 | FileCheck %s
7+
// REQUIRES: asan-dynamic-runtime
8+
// REQUIRES: asan-32-bits
9+
10+
#include <cassert>
11+
#include <stdio.h>
12+
#include <windows.h>
13+
extern "C" {
14+
#if defined(EXE)
15+
16+
int main(int argc, char **argv) {
17+
void *region_without_hooks = HeapAlloc(GetProcessHeap(), 0, 10);
18+
HMODULE lib = LoadLibraryA(argv[1]);
19+
assert(lib != INVALID_HANDLE_VALUE);
20+
assert(0 != FreeLibrary(lib));
21+
assert(0 != HeapFree(GetProcessHeap(), 0, region_without_hooks));
22+
HeapReAlloc(GetProcessHeap(), 0, region_without_hooks, 100); //should throw nested error
23+
}
24+
#elif defined(DLL)
25+
// This global is registered at startup.
26+
27+
BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
28+
fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
29+
fflush(0);
30+
return TRUE;
31+
}
32+
33+
// CHECK: in DLL(reason=1)
34+
// CHECK: in DLL(reason=0)
35+
// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
36+
37+
#else
38+
#error oops!
39+
#endif
40+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
3+
// XFAIL: asan-64-bits
4+
#include <cassert>
5+
#include <windows.h>
6+
7+
int main() {
8+
void *allocation = HeapAlloc(GetProcessHeap(), 0, 10);
9+
assert(allocation != 0);
10+
assert(HeapFree(GetProcessHeap(), 0, allocation));
11+
HeapFree(GetProcessHeap(), 0, allocation); //will dump
12+
assert(0 && "HeapFree double free should produce an ASAN dump\n");
13+
return 0;
14+
}
15+
16+
// CHECK: AddressSanitizer: attempting double-free on [[addr:0x[0-9a-fA-F]+]] in thread T0:
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t
2+
// RUN: %run %t 2>&1 | FileCheck %s
3+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
4+
// XFAIL: asan-64-bits
5+
#include <assert.h>
6+
#include <stdio.h>
7+
#include <windows.h>
8+
9+
extern "C" int
10+
__sanitizer_get_ownership(const volatile void *p);
11+
12+
int main() {
13+
char *buffer;
14+
buffer = (char *)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, 32);
15+
buffer[0] = 'a';
16+
assert(!__sanitizer_get_ownership(buffer));
17+
HeapFree(GetProcessHeap(), 0, buffer);
18+
puts("Okay");
19+
// CHECK: Okay
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t
2+
// RUN: %env_asan_opts=allocator_may_return_null=true %run %t
3+
// RUN: %env_asan_opts=allocator_may_return_null=true:windows_hook_rtl_allocators=true %run %t
4+
// XFAIL: asan-64-bits
5+
#include <windows.h>
6+
int main() {
7+
void *nope = HeapAlloc(GetProcessHeap(), 0, ((size_t)0) - 1);
8+
return (nope == nullptr) ? 0 : 1;
9+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include "sanitizer\allocator_interface.h"
2+
#include <cassert>
3+
#include <stdio.h>
4+
#include <windows.h>
5+
6+
// RUN: %clang_cl_asan %s -o%t
7+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
8+
// XFAIL: asan-64-bits
9+
10+
using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
11+
using ReAllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID, SIZE_T);
12+
13+
using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
14+
15+
int main() {
16+
HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
17+
if (!NtDllHandle) {
18+
puts("Couldn't load ntdll??");
19+
return -1;
20+
}
21+
22+
auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
23+
if (RtlAllocateHeap_ptr == 0) {
24+
puts("Couldn't find RtlAllocateHeap");
25+
return -1;
26+
}
27+
28+
auto RtlReAllocateHeap_ptr = (ReAllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
29+
if (RtlReAllocateHeap_ptr == 0) {
30+
puts("Couldn't find RtlReAllocateHeap");
31+
return -1;
32+
}
33+
34+
//owned by rtl
35+
void *alloc = RtlAllocateHeap_ptr(GetProcessHeap(),
36+
HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, 100);
37+
assert(alloc);
38+
for (int i = 0; i < 100; i++) {
39+
assert(((char *)alloc)[i] == 0);
40+
((char *)alloc)[i] = '\xcc';
41+
}
42+
43+
// still owned by rtl
44+
alloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
45+
HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, alloc, 500);
46+
assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
47+
for (int i = 0; i < 100; i++) {
48+
assert(((char *)alloc)[i] == '\xcc');
49+
}
50+
for (int i = 100; i < 500; i++) {
51+
assert(((char *)alloc)[i] == 0);
52+
((char *)alloc)[i] = '\xcc';
53+
}
54+
55+
//convert to asan owned
56+
void *realloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
57+
HEAP_ZERO_MEMORY, alloc, 600);
58+
alloc = nullptr;
59+
assert(realloc && __sanitizer_get_ownership(realloc));
60+
61+
for (int i = 0; i < 500; i++) {
62+
assert(((char *)realloc)[i] == '\xcc');
63+
}
64+
for (int i = 500; i < 600; i++) {
65+
assert(((char *)realloc)[i] == 0);
66+
((char *)realloc)[i] = '\xcc';
67+
}
68+
realloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
69+
HEAP_ZERO_MEMORY, realloc, 2048);
70+
assert(realloc && __sanitizer_get_ownership(realloc));
71+
72+
for (int i = 0; i < 600; i++) {
73+
assert(((char *)realloc)[i] == '\xcc');
74+
}
75+
for (int i = 600; i < 2048; i++) {
76+
assert(((char *)realloc)[i] == 0);
77+
((char *)realloc)[i] = '\xcc';
78+
}
79+
//convert back to rtl owned;
80+
alloc = RtlReAllocateHeap_ptr(GetProcessHeap(),
81+
HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, realloc, 100);
82+
assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
83+
for (int i = 0; i < 100; i++) {
84+
assert(((char *)alloc)[i] == '\xcc');
85+
((char *)alloc)[i] = 0;
86+
}
87+
88+
auto usable_size = HeapSize(GetProcessHeap(), 0, alloc);
89+
for (int i = 100; i < usable_size; i++) {
90+
assert(((char *)alloc)[i] == 0);
91+
}
92+
93+
printf("Success\n");
94+
}
95+
96+
// CHECK-NOT: Assertion failed:
97+
// CHECK-NOT: AddressSanitizer
98+
// CHECK: Success
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t
2+
// RUN: %run %t 2>&1 | FileCheck %s
3+
#include <stdio.h>
4+
#include <windows.h>
5+
6+
int main() {
7+
char *buffer;
8+
buffer = (char *)HeapAlloc(GetProcessHeap(), 0, 32),
9+
buffer[0] = 'a';
10+
HeapFree(GetProcessHeap(), 0, buffer);
11+
puts("Okay");
12+
// CHECK: Okay
13+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "sanitizer\allocator_interface.h"
2+
#include <cassert>
3+
#include <stdio.h>
4+
#include <windows.h>
5+
// RUN: %clang_cl_asan %s -o%t
6+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
7+
// XFAIL: asan-64-bits
8+
9+
int main() {
10+
//owned by rtl
11+
void *alloc = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, 100);
12+
assert(alloc);
13+
// still owned by rtl
14+
alloc = HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, alloc, 100);
15+
assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
16+
//convert to asan owned
17+
void *realloc = HeapReAlloc(GetProcessHeap(), 0, alloc, 500);
18+
alloc = nullptr;
19+
assert(realloc && __sanitizer_get_ownership(realloc));
20+
//convert back to rtl owned;
21+
alloc = HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, realloc, 100);
22+
assert(alloc && !__sanitizer_get_ownership(alloc) && HeapValidate(GetProcessHeap(), 0, alloc));
23+
printf("Success\n");
24+
}
25+
26+
// CHECK-NOT: assert
27+
// CHECK-NOT: AddressSanitizer
28+
// CHECK: Success
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
3+
// XFAIL: asan-64-bits
4+
#include <windows.h>
5+
6+
int main() {
7+
char *buffer;
8+
buffer = (char *)HeapAlloc(GetProcessHeap(), 0, 32),
9+
HeapFree(GetProcessHeap(), 0, buffer);
10+
buffer[0] = 'a';
11+
// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
12+
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
13+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cl_asan /Od -o %t %s
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
3+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=false %run %t 2>&1 | FileCheck %s
4+
// RUN: %clang_cl /Od -o %t %s
5+
// RUN: %run %t 2>&1 | FileCheck %s
6+
// XFAIL: asan-64-bits
7+
#include <cassert>
8+
#include <stdio.h>
9+
#include <windows.h>
10+
11+
int main() {
12+
HANDLE heap = HeapCreate(0, 0, 0);
13+
void *ptr = HeapAlloc(heap, 0, 4);
14+
assert(ptr);
15+
void *ptr2 = HeapReAlloc(heap, 0, ptr, 0);
16+
assert(ptr2);
17+
HeapFree(heap, 0, ptr2);
18+
fprintf(stderr, "passed!\n");
19+
}
20+
21+
// CHECK-NOT: double-free
22+
// CHECK-NOT: AddressSanitizer
23+
// CHECK: passed!
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
3+
// XFAIL: asan-64-bits
4+
#include <stdio.h>
5+
#include <windows.h>
6+
7+
int main() {
8+
char *oldbuf;
9+
size_t sz = 8;
10+
HANDLE procHeap = GetProcessHeap();
11+
oldbuf = (char *)HeapAlloc(procHeap, 0, sz);
12+
char *newbuf = oldbuf;
13+
while (oldbuf == newbuf) {
14+
sz *= 2;
15+
newbuf = (char *)HeapReAlloc(procHeap, 0, oldbuf, sz);
16+
}
17+
18+
newbuf[0] = 'a';
19+
oldbuf[0] = 'a';
20+
// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
21+
// CHECK: WRITE of size 1 at [[WRITE2:0x[0-9a-f]+]] thread T0
22+
// CHECK: #0 {{0x[0-9a-f]+ in main.*}}:[[@LINE-3]]
23+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %clang_cl_asan /Od /MT -o %t %s
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
3+
// XFAIL: asan-64-bits
4+
#include <cassert>
5+
#include <iostream>
6+
#include <windows.h>
7+
8+
int main() {
9+
void *ptr = malloc(0);
10+
if (ptr)
11+
std::cerr << "allocated!\n";
12+
((char *)ptr)[0] = '\xff'; //check this 'allocate 1 instead of 0' hack hasn't changed
13+
14+
free(ptr);
15+
16+
/*
17+
HeapAlloc hack for our asan interceptor is to change 0
18+
sized allocations to size 1 to avoid weird inconsistencies
19+
between how realloc and heaprealloc handle 0 size allocations.
20+
21+
Note this test relies on these instructions being intercepted.
22+
Without ASAN HeapRealloc on line 27 would return a ptr whose
23+
HeapSize would be 0. This test makes sure that the underlying behavior
24+
of our hack hasn't changed underneath us.
25+
26+
We can get rid of the test (or change it to test for the correct
27+
behavior) once we fix the interceptor or write a different allocator
28+
to handle 0 sized allocations properly by default.
29+
30+
*/
31+
ptr = HeapAlloc(GetProcessHeap(), 0, 0);
32+
if (!ptr)
33+
return 1;
34+
void *ptr2 = HeapReAlloc(GetProcessHeap(), 0, ptr, 0);
35+
if (!ptr2)
36+
return 1;
37+
size_t heapsize = HeapSize(GetProcessHeap(), 0, ptr2);
38+
if (heapsize != 1) { // will be 0 without ASAN turned on
39+
std::cerr << "HeapAlloc size failure! " << heapsize << " != 1\n";
40+
return 1;
41+
}
42+
void *ptr3 = HeapReAlloc(GetProcessHeap(), 0, ptr2, 3);
43+
if (!ptr3)
44+
return 1;
45+
heapsize = HeapSize(GetProcessHeap(), 0, ptr3);
46+
47+
if (heapsize != 3) {
48+
std::cerr << "HeapAlloc size failure! " << heapsize << " != 3\n";
49+
return 1;
50+
}
51+
HeapFree(GetProcessHeap(), 0, ptr3);
52+
return 0;
53+
}
54+
55+
// CHECK: allocated!
56+
// CHECK-NOT: heap-buffer-overflow
57+
// CHECK-NOT: AddressSanitizer
58+
// CHECK-NOT: HeapAlloc size failure!

‎compiler-rt/test/asan/TestCases/Windows/heaprealloc_zero_size.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// RUN: %clang_cl_asan /Od -o %t %s
2-
// RUN: %run %t 2>&1 | FileCheck %s
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
3+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=false %run %t 2>&1 | FileCheck %s
34
// RUN: %clang_cl /Od -o %t %s
45
// RUN: %run %t 2>&1 | FileCheck %s
6+
// XFAIL: asan-64-bits
57
#include <cassert>
68
#include <stdio.h>
79
#include<windows.h>

‎compiler-rt/test/asan/TestCases/Windows/queue_user_work_item_report.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ DWORD CALLBACK work_item(LPVOID) {
99
int subscript = -1;
1010
volatile char stack_buffer[42];
1111
stack_buffer[subscript] = 42;
12-
// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]]
13-
// CHECK: WRITE of size 1 at [[ADDR]] thread T1
14-
// CHECK: {{#0 .* work_item.*queue_user_work_item_report.cc}}:[[@LINE-3]]
12+
// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]]
13+
// CHECK: WRITE of size 1 at [[ADDR]] thread T{{[0-9]+}}
14+
// CHECK: {{#0 .* work_item.*queue_user_work_item_report.cc}}:[[@LINE-3]]
1515
SetEvent(done);
1616
return 0;
1717
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t /MD
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
3+
// XFAIL: asan-64-bits
4+
// REQUIRES: asan-rtl-heap-interception
5+
6+
#include <stdio.h>
7+
#include <windows.h>
8+
9+
using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
10+
using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
11+
12+
int main() {
13+
HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
14+
if (!NtDllHandle) {
15+
puts("Couldn't load ntdll??");
16+
return -1;
17+
}
18+
19+
auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
20+
if (RtlAllocateHeap_ptr == 0) {
21+
puts("Couldn't RtlAllocateHeap");
22+
return -1;
23+
}
24+
25+
char *buffer;
26+
buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32),
27+
buffer[33] = 'a';
28+
// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
29+
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
30+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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+
// REQUIRES: asan-rtl-heap-interception
7+
8+
#include <cassert>
9+
#include <stdio.h>
10+
#include <windows.h>
11+
12+
extern "C" {
13+
#if defined(EXE)
14+
using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
15+
using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
16+
17+
int main(int argc, char **argv) {
18+
HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
19+
if (!NtDllHandle) {
20+
puts("Couldn't load ntdll??");
21+
return -1;
22+
}
23+
24+
auto RtlAllocateHeap_ptr =
25+
(AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
26+
if (RtlAllocateHeap_ptr == 0) {
27+
puts("Couldn't RtlAllocateHeap");
28+
return -1;
29+
}
30+
31+
auto RtlFreeHeap_ptr =
32+
(FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
33+
if (RtlFreeHeap_ptr == 0) {
34+
puts("Couldn't get RtlFreeHeap");
35+
return -1;
36+
}
37+
38+
char *buffer;
39+
buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32);
40+
41+
HMODULE lib = LoadLibraryA(argv[1]);
42+
assert(lib != INVALID_HANDLE_VALUE);
43+
assert(0 != FreeLibrary(lib));
44+
45+
if (!RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer)) {
46+
puts("Couldn't RtlFreeHeap");
47+
return -1;
48+
}
49+
// Because this pointer was allocated pre-hooking,
50+
// this will dump as a nested bug. Asan attempts to free
51+
// the pointer and AV's, so the ASAN exception handler
52+
// will dump as a 'nested bug'.
53+
RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer);
54+
}
55+
56+
#elif defined(DLL)
57+
// This global is registered at startup.
58+
59+
BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
60+
fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
61+
fflush(0);
62+
return TRUE;
63+
}
64+
65+
// CHECK: in DLL(reason=1)
66+
// CHECK: in DLL(reason=0)
67+
// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
68+
69+
#else
70+
#error oops!
71+
#endif
72+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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+
// REQUIRES: asan-rtl-heap-interception
7+
8+
#include <cassert>
9+
#include <stdio.h>
10+
#include <windows.h>
11+
12+
extern "C" {
13+
#if defined(EXE)
14+
using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
15+
using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
16+
using RtlReAllocateHeapPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID, SIZE_T);
17+
18+
int main(int argc, char **argv) {
19+
HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
20+
if (!NtDllHandle) {
21+
puts("Couldn't load ntdll??");
22+
return -1;
23+
}
24+
25+
auto RtlAllocateHeap_ptr =
26+
(AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
27+
if (RtlAllocateHeap_ptr == 0) {
28+
puts("Couldn't RtlAllocateHeap");
29+
return -1;
30+
}
31+
32+
auto RtlFreeHeap_ptr =
33+
(FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
34+
if (RtlFreeHeap_ptr == 0) {
35+
puts("Couldn't get RtlFreeHeap");
36+
return -1;
37+
}
38+
39+
auto RtlReAllocateHeap_ptr =
40+
(RtlReAllocateHeapPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
41+
if (RtlReAllocateHeap_ptr == 0) {
42+
puts("Couldn't get rtlreallocateheap\n");
43+
return -1;
44+
}
45+
46+
char *buffer;
47+
buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32);
48+
49+
HMODULE lib = LoadLibraryA(argv[1]);
50+
assert(lib != INVALID_HANDLE_VALUE);
51+
assert(0 != FreeLibrary(lib));
52+
53+
if (!RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer)) {
54+
puts("Couldn't RtlFreeHeap");
55+
return -1;
56+
}
57+
RtlReAllocateHeap_ptr(GetProcessHeap(), 0, buffer, 100); // should dump
58+
}
59+
60+
#elif defined(DLL)
61+
// This global is registered at startup.
62+
63+
BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
64+
fprintf(stderr, "in DLL(reason=%d)\n", (int)reason);
65+
fflush(0);
66+
return TRUE;
67+
}
68+
69+
// CHECK: in DLL(reason=1)
70+
// CHECK: in DLL(reason=0)
71+
// CHECK: AddressSanitizer: nested bug in the same thread, aborting.
72+
73+
#else
74+
#error oops!
75+
#endif
76+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t /MD
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true %run %t 2>&1 | FileCheck %s
3+
// XFAIL: asan-64-bits
4+
// REQUIRES: asan-rtl-heap-interception
5+
6+
#include <assert.h>
7+
#include <stdio.h>
8+
#include <windows.h>
9+
10+
extern "C" int __sanitizer_get_ownership(const volatile void *p);
11+
using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
12+
using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
13+
14+
int main() {
15+
HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
16+
if (!NtDllHandle) {
17+
puts("Couldn't load ntdll??");
18+
return -1;
19+
}
20+
21+
auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
22+
if (RtlAllocateHeap_ptr == 0) {
23+
puts("Couldn't RtlAllocateHeap");
24+
return -1;
25+
}
26+
27+
auto RtlFreeHeap_ptr = (FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
28+
if (RtlFreeHeap_ptr == 0) {
29+
puts("Couldn't RtlFreeHeap");
30+
return -1;
31+
}
32+
33+
char *winbuf;
34+
char *asanbuf;
35+
winbuf = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, 32),
36+
asanbuf = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 32),
37+
winbuf[0] = 'a';
38+
assert(!__sanitizer_get_ownership(winbuf));
39+
assert(__sanitizer_get_ownership(asanbuf));
40+
41+
RtlFreeHeap_ptr(GetProcessHeap(), 0, winbuf);
42+
RtlFreeHeap_ptr(GetProcessHeap(), 0, asanbuf);
43+
puts("Okay");
44+
// CHECK: Okay
45+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %clang_cl_asan -O0 %s -Fe%t /MD
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
3+
// XFAIL: asan-64-bits
4+
// REQUIRES: asan-rtl-heap-interception
5+
6+
#include <assert.h>
7+
#include <stdio.h>
8+
#include <windows.h>
9+
10+
using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
11+
using ReAllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID, SIZE_T);
12+
using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
13+
14+
int main() {
15+
HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
16+
if (!NtDllHandle) {
17+
puts("Couldn't load ntdll??");
18+
return -1;
19+
}
20+
21+
auto RtlAllocateHeap_ptr = (AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
22+
if (RtlAllocateHeap_ptr == 0) {
23+
puts("Couldn't find RtlAllocateHeap");
24+
return -1;
25+
}
26+
27+
auto RtlReAllocateHeap_ptr = (ReAllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
28+
if (RtlReAllocateHeap_ptr == 0) {
29+
puts("Couldn't find RtlReAllocateHeap");
30+
return -1;
31+
}
32+
33+
char *buffer;
34+
SIZE_T buffer_size = 32;
35+
SIZE_T new_buffer_size = buffer_size * 2;
36+
37+
buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size);
38+
assert(buffer != nullptr);
39+
// Check that the buffer is zeroed.
40+
for (SIZE_T i = 0; i < buffer_size; ++i) {
41+
assert(buffer[i] == 0);
42+
}
43+
memset(buffer, 0xcc, buffer_size);
44+
45+
// Zero the newly allocated memory.
46+
buffer = (char *)RtlReAllocateHeap_ptr(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, new_buffer_size);
47+
assert(buffer != nullptr);
48+
// Check that the first part of the buffer still has the old contents.
49+
for (SIZE_T i = 0; i < buffer_size; ++i) {
50+
assert(buffer[i] == (char)0xcc);
51+
}
52+
// Check that the new part of the buffer is zeroed.
53+
for (SIZE_T i = buffer_size; i < new_buffer_size; ++i) {
54+
assert(buffer[i] == 0x0);
55+
}
56+
57+
// Shrink the buffer back down.
58+
buffer = (char *)RtlReAllocateHeap_ptr(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, buffer_size);
59+
assert(buffer != nullptr);
60+
// Check that the first part of the buffer still has the old contents.
61+
for (SIZE_T i = 0; i < buffer_size; ++i) {
62+
assert(buffer[i] == (char)0xcc);
63+
}
64+
65+
buffer[buffer_size + 1] = 'a';
66+
// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
67+
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
68+
}

0 commit comments

Comments
 (0)
Please sign in to comment.