Skip to content

Commit d349daa

Browse files
authored
[win/asan] Improve SharedReAlloc with HEAP_REALLOC_IN_PLACE_ONLY. (#132558)
Currently with HEAP_REALLOC_IN_PLACE_ONLY a new allocation gets returned with the content copied from the original pointer, which gets freed. But applications may rely on HEAP_REALLOC_IN_PLACE_ONLY returning the same pointer as they give as input to e.g. RtlReAllocateHeap. If e.g. growing is not possible it fails without modifying the input pointer. Downside of this patch is, it won't detect accesses to the area getting "free" by a shrinking reallocation.
1 parent cc0fb0d commit d349daa

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

compiler-rt/lib/asan/asan_malloc_win.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,22 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc,
322322
}
323323
}
324324

325+
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) {
326+
size_t old_usable_size = asan_malloc_usable_size(lpMem, pc, bp);
327+
if (dwBytes == old_usable_size) {
328+
// Nothing to change, return the current pointer.
329+
return lpMem;
330+
} else if (dwBytes >= old_usable_size) {
331+
// Growing with HEAP_REALLOC_IN_PLACE_ONLY is not supported.
332+
return nullptr;
333+
} else {
334+
// Shrinking with HEAP_REALLOC_IN_PLACE_ONLY is not yet supported.
335+
// For now return the current pointer and
336+
// leave the allocation size as it is.
337+
return lpMem;
338+
}
339+
}
340+
325341
if (ownershipState == ASAN && !only_asan_supported_flags) {
326342
// Conversion to unsupported flags allocation,
327343
// transfer this allocation back to the original allocator.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: %clang_cl_asan %Od %s %Fe%t %MD
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true not %run %t 2>&1 | FileCheck %s
3+
4+
#include <stdio.h>
5+
#include <windows.h>
6+
7+
using AllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, SIZE_T);
8+
using ReAllocateFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID, SIZE_T);
9+
using FreeFunctionPtr = PVOID(__stdcall *)(PVOID, ULONG, PVOID);
10+
11+
int main() {
12+
HMODULE NtDllHandle = GetModuleHandle("ntdll.dll");
13+
if (!NtDllHandle) {
14+
fputs("Couldn't load ntdll??\n", stderr);
15+
return -1;
16+
}
17+
18+
auto RtlAllocateHeap_ptr =
19+
(AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
20+
if (RtlAllocateHeap_ptr == 0) {
21+
fputs("Couldn't RtlAllocateHeap\n", stderr);
22+
return -1;
23+
}
24+
25+
auto RtlReAllocateHeap_ptr =
26+
(ReAllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
27+
if (RtlReAllocateHeap_ptr == 0) {
28+
fputs("Couldn't find RtlReAllocateHeap\n", stderr);
29+
return -1;
30+
}
31+
32+
auto RtlFreeHeap_ptr =
33+
(FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
34+
if (RtlFreeHeap_ptr == 0) {
35+
fputs("Couldn't RtlFreeHeap\n", stderr);
36+
return -1;
37+
}
38+
39+
char *ptr1;
40+
char *ptr2;
41+
ptr2 = ptr1 = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 15);
42+
if (ptr1)
43+
fputs("Okay alloc\n", stderr);
44+
// CHECK: Okay alloc
45+
46+
// TODO: Growing is currently not supported
47+
ptr2 = (char *)RtlReAllocateHeap_ptr(GetProcessHeap(),
48+
HEAP_REALLOC_IN_PLACE_ONLY, ptr1, 23);
49+
if (ptr2 == NULL)
50+
fputs("Okay grow failed\n", stderr);
51+
// CHECK: Okay grow failed
52+
53+
// TODO: Shrinking is currently not supported
54+
ptr2 = (char *)RtlReAllocateHeap_ptr(GetProcessHeap(),
55+
HEAP_REALLOC_IN_PLACE_ONLY, ptr1, 7);
56+
if (ptr2 == ptr1)
57+
fputs("Okay shrinking return the original pointer\n", stderr);
58+
// CHECK: Okay shrinking return the original pointer
59+
60+
ptr1[7] = 'a';
61+
fputs("Okay 7\n", stderr);
62+
// CHECK: Okay 7
63+
64+
// TODO: Writing behind the shrinked part is currently not detected.
65+
// Therefore test writing behind the original allocation for now.
66+
ptr1[16] = 'a';
67+
// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
68+
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
69+
70+
RtlFreeHeap_ptr(GetProcessHeap(), 0, ptr1);
71+
}

0 commit comments

Comments
 (0)