Skip to content

Commit 213f036

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 213f036

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

compiler-rt/lib/asan/asan_malloc_win.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,23 @@ 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, old_usable_size - dwBytes);
331+
}
332+
__asan_unpoison_memory_region((char*)lpMem, dwBytes);
333+
return lpMem;
334+
} else {
335+
return nullptr;
336+
}
337+
}
338+
326339
// Conversion to unsupported flags allocation,
327340
// transfer this allocation back to the original allocator.
328341
void *replacement_alloc = allocFunc(hHeap, dwFlags, dwBytes);
329-
size_t old_usable_size = 0;
330342
if (replacement_alloc) {
331-
old_usable_size = asan_malloc_usable_size(lpMem, pc, bp);
332343
REAL(memcpy)(replacement_alloc, lpMem,
333344
Min<size_t>(dwBytes, old_usable_size));
334345
asan_free(lpMem, &stack, FROM_MALLOC);
@@ -348,6 +359,7 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc,
348359
}
349360
// asan_realloc will never reallocate in place, so for now this flag is
350361
// unsupported until we figure out a way to fake this.
362+
// Small exception when shrinking or staying below the inital size, see above.
351363
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)
352364
return nullptr;
353365

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

0 commit comments

Comments
 (0)