Skip to content

Commit bfcb81b

Browse files
committed
[win/asan] Improve SharedReAlloc with HEAP_REALLOC_IN_PLACE_ONLY.
This patch allows reallocations in place if the size is below or equal to the initial allocated size. Currently it prints only a "use-after-poison" message, not a proper "heap-buffer-overflow" with a hint to a reallocation.
1 parent db7475a commit bfcb81b

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

compiler-rt/lib/asan/asan_malloc_win.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,24 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc,
323323
}
324324

325325
if (ownershipState == ASAN && !only_asan_supported_flags) {
326+
size_t old_usable_size = asan_malloc_usable_size(lpMem, pc, bp);
327+
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) {
328+
if (dwBytes >= 1 && dwBytes <= old_usable_size) {
329+
if (dwBytes < old_usable_size) {
330+
__asan_poison_memory_region((char *)lpMem + dwBytes,
331+
old_usable_size - dwBytes);
332+
}
333+
__asan_unpoison_memory_region((char *)lpMem, dwBytes);
334+
return lpMem;
335+
} else {
336+
return nullptr;
337+
}
338+
}
339+
326340
// Conversion to unsupported flags allocation,
327341
// transfer this allocation back to the original allocator.
328342
void *replacement_alloc = allocFunc(hHeap, dwFlags, dwBytes);
329-
size_t old_usable_size = 0;
330343
if (replacement_alloc) {
331-
old_usable_size = asan_malloc_usable_size(lpMem, pc, bp);
332344
REAL(memcpy)(replacement_alloc, lpMem,
333345
Min<size_t>(dwBytes, old_usable_size));
334346
asan_free(lpMem, &stack, FROM_MALLOC);
@@ -348,6 +360,7 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc,
348360
}
349361
// asan_realloc will never reallocate in place, so for now this flag is
350362
// unsupported until we figure out a way to fake this.
363+
// Small exception when shrinking or staying below the inital size, see above.
351364
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)
352365
return nullptr;
353366

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// RUN: %clang_cl_asan %Od %s %Fe%t %MD
2+
// RUN: %env_asan_opts=windows_hook_rtl_allocators=true:halt_on_error=false 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+
puts("Couldn't load ntdll??");
15+
return -1;
16+
}
17+
18+
auto RtlAllocateHeap_ptr =
19+
(AllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlAllocateHeap");
20+
if (RtlAllocateHeap_ptr == 0) {
21+
puts("Couldn't RtlAllocateHeap");
22+
return -1;
23+
}
24+
25+
auto RtlReAllocateHeap_ptr =
26+
(ReAllocateFunctionPtr)GetProcAddress(NtDllHandle, "RtlReAllocateHeap");
27+
if (RtlReAllocateHeap_ptr == 0) {
28+
puts("Couldn't find RtlReAllocateHeap");
29+
return -1;
30+
}
31+
32+
auto RtlFreeHeap_ptr =
33+
(FreeFunctionPtr)GetProcAddress(NtDllHandle, "RtlFreeHeap");
34+
if (RtlFreeHeap_ptr == 0) {
35+
puts("Couldn't RtlFreeHeap");
36+
return -1;
37+
}
38+
39+
char *buffer;
40+
buffer = (char *)RtlAllocateHeap_ptr(GetProcessHeap(), 0, 48),
41+
42+
RtlReAllocateHeap_ptr(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, buffer,
43+
16);
44+
buffer[15] = 'a';
45+
puts("Okay 15");
46+
fflush(stdout);
47+
// CHECK: Okay 15
48+
49+
RtlReAllocateHeap_ptr(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, buffer,
50+
32);
51+
buffer[31] = 'a';
52+
puts("Okay 31");
53+
fflush(stdout);
54+
// CHECK: Okay 31
55+
56+
buffer[32] = 'a';
57+
// CHECK: AddressSanitizer: use-after-poison on address [[ADDR:0x[0-9a-f]+]]
58+
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
59+
60+
RtlFreeHeap_ptr(GetProcessHeap(), 0, buffer);
61+
}

0 commit comments

Comments
 (0)