Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/asan/asan_malloc_win.cpp
35233 views
1
//===-- asan_malloc_win.cpp -----------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file is a part of AddressSanitizer, an address sanity checker.
10
//
11
// Windows-specific malloc interception.
12
//===----------------------------------------------------------------------===//
13
14
#include "sanitizer_common/sanitizer_allocator_interface.h"
15
#include "sanitizer_common/sanitizer_platform.h"
16
#if SANITIZER_WINDOWS
17
#include "asan_allocator.h"
18
#include "asan_interceptors.h"
19
#include "asan_internal.h"
20
#include "asan_stack.h"
21
#include "interception/interception.h"
22
#include <stddef.h>
23
24
// Intentionally not including windows.h here, to avoid the risk of
25
// pulling in conflicting declarations of these functions. (With mingw-w64,
26
// there's a risk of windows.h pulling in stdint.h.)
27
typedef int BOOL;
28
typedef void *HANDLE;
29
typedef const void *LPCVOID;
30
typedef void *LPVOID;
31
32
typedef unsigned long DWORD;
33
constexpr unsigned long HEAP_ZERO_MEMORY = 0x00000008;
34
constexpr unsigned long HEAP_REALLOC_IN_PLACE_ONLY = 0x00000010;
35
constexpr unsigned long HEAP_ALLOCATE_SUPPORTED_FLAGS = (HEAP_ZERO_MEMORY);
36
constexpr unsigned long HEAP_ALLOCATE_UNSUPPORTED_FLAGS =
37
(~HEAP_ALLOCATE_SUPPORTED_FLAGS);
38
constexpr unsigned long HEAP_FREE_UNSUPPORTED_FLAGS =
39
(~HEAP_ALLOCATE_SUPPORTED_FLAGS);
40
constexpr unsigned long HEAP_REALLOC_UNSUPPORTED_FLAGS =
41
(~HEAP_ALLOCATE_SUPPORTED_FLAGS);
42
43
44
extern "C" {
45
LPVOID WINAPI HeapAlloc(HANDLE hHeap, DWORD dwFlags, size_t dwBytes);
46
LPVOID WINAPI HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem,
47
size_t dwBytes);
48
BOOL WINAPI HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
49
size_t WINAPI HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);
50
51
BOOL WINAPI HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);
52
}
53
54
using namespace __asan;
55
56
// MT: Simply defining functions with the same signature in *.obj
57
// files overrides the standard functions in the CRT.
58
// MD: Memory allocation functions are defined in the CRT .dll,
59
// so we have to intercept them before they are called for the first time.
60
61
#if ASAN_DYNAMIC
62
# define ALLOCATION_FUNCTION_ATTRIBUTE
63
#else
64
# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
65
#endif
66
67
extern "C" {
68
ALLOCATION_FUNCTION_ATTRIBUTE
69
size_t _msize(void *ptr) {
70
GET_CURRENT_PC_BP_SP;
71
(void)sp;
72
return asan_malloc_usable_size(ptr, pc, bp);
73
}
74
75
ALLOCATION_FUNCTION_ATTRIBUTE
76
size_t _msize_base(void *ptr) {
77
return _msize(ptr);
78
}
79
80
ALLOCATION_FUNCTION_ATTRIBUTE
81
void free(void *ptr) {
82
GET_STACK_TRACE_FREE;
83
return asan_free(ptr, &stack, FROM_MALLOC);
84
}
85
86
ALLOCATION_FUNCTION_ATTRIBUTE
87
void _free_dbg(void *ptr, int) {
88
free(ptr);
89
}
90
91
ALLOCATION_FUNCTION_ATTRIBUTE
92
void _free_base(void *ptr) {
93
free(ptr);
94
}
95
96
ALLOCATION_FUNCTION_ATTRIBUTE
97
void *malloc(size_t size) {
98
GET_STACK_TRACE_MALLOC;
99
return asan_malloc(size, &stack);
100
}
101
102
ALLOCATION_FUNCTION_ATTRIBUTE
103
void *_malloc_base(size_t size) {
104
return malloc(size);
105
}
106
107
ALLOCATION_FUNCTION_ATTRIBUTE
108
void *_malloc_dbg(size_t size, int, const char *, int) {
109
return malloc(size);
110
}
111
112
ALLOCATION_FUNCTION_ATTRIBUTE
113
void *calloc(size_t nmemb, size_t size) {
114
GET_STACK_TRACE_MALLOC;
115
return asan_calloc(nmemb, size, &stack);
116
}
117
118
ALLOCATION_FUNCTION_ATTRIBUTE
119
void *_calloc_base(size_t nmemb, size_t size) {
120
return calloc(nmemb, size);
121
}
122
123
ALLOCATION_FUNCTION_ATTRIBUTE
124
void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
125
return calloc(nmemb, size);
126
}
127
128
ALLOCATION_FUNCTION_ATTRIBUTE
129
void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
130
return calloc(nmemb, size);
131
}
132
133
ALLOCATION_FUNCTION_ATTRIBUTE
134
void *realloc(void *ptr, size_t size) {
135
GET_STACK_TRACE_MALLOC;
136
return asan_realloc(ptr, size, &stack);
137
}
138
139
ALLOCATION_FUNCTION_ATTRIBUTE
140
void *_realloc_dbg(void *ptr, size_t size, int) {
141
UNREACHABLE("_realloc_dbg should not exist!");
142
return 0;
143
}
144
145
ALLOCATION_FUNCTION_ATTRIBUTE
146
void *_realloc_base(void *ptr, size_t size) {
147
return realloc(ptr, size);
148
}
149
150
ALLOCATION_FUNCTION_ATTRIBUTE
151
void *_recalloc(void *p, size_t n, size_t elem_size) {
152
if (!p)
153
return calloc(n, elem_size);
154
const size_t size = n * elem_size;
155
if (elem_size != 0 && size / elem_size != n)
156
return 0;
157
158
size_t old_size = _msize(p);
159
void *new_alloc = malloc(size);
160
if (new_alloc) {
161
REAL(memcpy)(new_alloc, p, Min<size_t>(size, old_size));
162
if (old_size < size)
163
REAL(memset)(((u8 *)new_alloc) + old_size, 0, size - old_size);
164
free(p);
165
}
166
return new_alloc;
167
}
168
169
ALLOCATION_FUNCTION_ATTRIBUTE
170
void *_recalloc_base(void *p, size_t n, size_t elem_size) {
171
return _recalloc(p, n, elem_size);
172
}
173
174
ALLOCATION_FUNCTION_ATTRIBUTE
175
void *_expand(void *memblock, size_t size) {
176
// _expand is used in realloc-like functions to resize the buffer if possible.
177
// We don't want memory to stand still while resizing buffers, so return 0.
178
return 0;
179
}
180
181
ALLOCATION_FUNCTION_ATTRIBUTE
182
void *_expand_dbg(void *memblock, size_t size) {
183
return _expand(memblock, size);
184
}
185
186
// TODO(timurrrr): Might want to add support for _aligned_* allocation
187
// functions to detect a bit more bugs. Those functions seem to wrap malloc().
188
189
int _CrtDbgReport(int, const char*, int,
190
const char*, const char*, ...) {
191
ShowStatsAndAbort();
192
}
193
194
int _CrtDbgReportW(int reportType, const wchar_t*, int,
195
const wchar_t*, const wchar_t*, ...) {
196
ShowStatsAndAbort();
197
}
198
199
int _CrtSetReportMode(int, int) {
200
return 0;
201
}
202
} // extern "C"
203
204
#define OWNED_BY_RTL(heap, memory) \
205
(!__sanitizer_get_ownership(memory) && HeapValidate(heap, 0, memory))
206
207
INTERCEPTOR_WINAPI(size_t, HeapSize, HANDLE hHeap, DWORD dwFlags,
208
LPCVOID lpMem) {
209
// If the RTL allocators are hooked we need to check whether the ASAN
210
// allocator owns the pointer we're about to use. Allocations occur before
211
// interception takes place, so if it is not owned by the RTL heap we can
212
// pass it to the ASAN heap for inspection.
213
if (flags()->windows_hook_rtl_allocators) {
214
if (!AsanInited() || OWNED_BY_RTL(hHeap, lpMem))
215
return REAL(HeapSize)(hHeap, dwFlags, lpMem);
216
} else {
217
CHECK(dwFlags == 0 && "unsupported heap flags");
218
}
219
GET_CURRENT_PC_BP_SP;
220
(void)sp;
221
return asan_malloc_usable_size(lpMem, pc, bp);
222
}
223
224
INTERCEPTOR_WINAPI(LPVOID, HeapAlloc, HANDLE hHeap, DWORD dwFlags,
225
size_t dwBytes) {
226
// If the ASAN runtime is not initialized, or we encounter an unsupported
227
// flag, fall back to the original allocator.
228
if (flags()->windows_hook_rtl_allocators) {
229
if (UNLIKELY(!AsanInited() ||
230
(dwFlags & HEAP_ALLOCATE_UNSUPPORTED_FLAGS) != 0)) {
231
return REAL(HeapAlloc)(hHeap, dwFlags, dwBytes);
232
}
233
} else {
234
// In the case that we don't hook the rtl allocators,
235
// this becomes an assert since there is no failover to the original
236
// allocator.
237
CHECK((HEAP_ALLOCATE_UNSUPPORTED_FLAGS & dwFlags) != 0 &&
238
"unsupported flags");
239
}
240
GET_STACK_TRACE_MALLOC;
241
void *p = asan_malloc(dwBytes, &stack);
242
// Reading MSDN suggests that the *entire* usable allocation is zeroed out.
243
// Otherwise it is difficult to HeapReAlloc with HEAP_ZERO_MEMORY.
244
// https://blogs.msdn.microsoft.com/oldnewthing/20120316-00/?p=8083
245
if (p && (dwFlags & HEAP_ZERO_MEMORY)) {
246
GET_CURRENT_PC_BP_SP;
247
(void)sp;
248
auto usable_size = asan_malloc_usable_size(p, pc, bp);
249
internal_memset(p, 0, usable_size);
250
}
251
return p;
252
}
253
254
INTERCEPTOR_WINAPI(BOOL, HeapFree, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
255
// Heap allocations happen before this function is hooked, so we must fall
256
// back to the original function if the pointer is not from the ASAN heap,
257
// or unsupported flags are provided.
258
if (flags()->windows_hook_rtl_allocators) {
259
if (OWNED_BY_RTL(hHeap, lpMem))
260
return REAL(HeapFree)(hHeap, dwFlags, lpMem);
261
} else {
262
CHECK((HEAP_FREE_UNSUPPORTED_FLAGS & dwFlags) != 0 && "unsupported flags");
263
}
264
GET_STACK_TRACE_FREE;
265
asan_free(lpMem, &stack, FROM_MALLOC);
266
return true;
267
}
268
269
namespace __asan {
270
using AllocFunction = LPVOID(WINAPI *)(HANDLE, DWORD, size_t);
271
using ReAllocFunction = LPVOID(WINAPI *)(HANDLE, DWORD, LPVOID, size_t);
272
using SizeFunction = size_t(WINAPI *)(HANDLE, DWORD, LPVOID);
273
using FreeFunction = BOOL(WINAPI *)(HANDLE, DWORD, LPVOID);
274
275
void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc,
276
FreeFunction freeFunc, AllocFunction allocFunc,
277
HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, size_t dwBytes) {
278
CHECK(reallocFunc && heapSizeFunc && freeFunc && allocFunc);
279
GET_STACK_TRACE_MALLOC;
280
GET_CURRENT_PC_BP_SP;
281
(void)sp;
282
if (flags()->windows_hook_rtl_allocators) {
283
enum AllocationOwnership { NEITHER = 0, ASAN = 1, RTL = 2 };
284
AllocationOwnership ownershipState;
285
bool owned_rtlalloc = false;
286
bool owned_asan = __sanitizer_get_ownership(lpMem);
287
288
if (!owned_asan)
289
owned_rtlalloc = HeapValidate(hHeap, 0, lpMem);
290
291
if (owned_asan && !owned_rtlalloc)
292
ownershipState = ASAN;
293
else if (!owned_asan && owned_rtlalloc)
294
ownershipState = RTL;
295
else if (!owned_asan && !owned_rtlalloc)
296
ownershipState = NEITHER;
297
298
// If this heap block which was allocated before the ASAN
299
// runtime came up, use the real HeapFree function.
300
if (UNLIKELY(!AsanInited())) {
301
return reallocFunc(hHeap, dwFlags, lpMem, dwBytes);
302
}
303
bool only_asan_supported_flags =
304
(HEAP_REALLOC_UNSUPPORTED_FLAGS & dwFlags) == 0;
305
306
if (ownershipState == RTL ||
307
(ownershipState == NEITHER && !only_asan_supported_flags)) {
308
if (only_asan_supported_flags) {
309
// if this is a conversion to ASAN upported flags, transfer this
310
// allocation to the ASAN allocator
311
void *replacement_alloc;
312
if (dwFlags & HEAP_ZERO_MEMORY)
313
replacement_alloc = asan_calloc(1, dwBytes, &stack);
314
else
315
replacement_alloc = asan_malloc(dwBytes, &stack);
316
if (replacement_alloc) {
317
size_t old_size = heapSizeFunc(hHeap, dwFlags, lpMem);
318
if (old_size == ((size_t)0) - 1) {
319
asan_free(replacement_alloc, &stack, FROM_MALLOC);
320
return nullptr;
321
}
322
REAL(memcpy)(replacement_alloc, lpMem, old_size);
323
freeFunc(hHeap, dwFlags, lpMem);
324
}
325
return replacement_alloc;
326
} else {
327
// owned by rtl or neither with unsupported ASAN flags,
328
// just pass back to original allocator
329
CHECK(ownershipState == RTL || ownershipState == NEITHER);
330
CHECK(!only_asan_supported_flags);
331
return reallocFunc(hHeap, dwFlags, lpMem, dwBytes);
332
}
333
}
334
335
if (ownershipState == ASAN && !only_asan_supported_flags) {
336
// Conversion to unsupported flags allocation,
337
// transfer this allocation back to the original allocator.
338
void *replacement_alloc = allocFunc(hHeap, dwFlags, dwBytes);
339
size_t old_usable_size = 0;
340
if (replacement_alloc) {
341
old_usable_size = asan_malloc_usable_size(lpMem, pc, bp);
342
REAL(memcpy)(replacement_alloc, lpMem,
343
Min<size_t>(dwBytes, old_usable_size));
344
asan_free(lpMem, &stack, FROM_MALLOC);
345
}
346
return replacement_alloc;
347
}
348
349
CHECK((ownershipState == ASAN || ownershipState == NEITHER) &&
350
only_asan_supported_flags);
351
// At this point we should either be ASAN owned with ASAN supported flags
352
// or we owned by neither and have supported flags.
353
// Pass through even when it's neither since this could be a null realloc or
354
// UAF that ASAN needs to catch.
355
} else {
356
CHECK((HEAP_REALLOC_UNSUPPORTED_FLAGS & dwFlags) != 0 &&
357
"unsupported flags");
358
}
359
// asan_realloc will never reallocate in place, so for now this flag is
360
// unsupported until we figure out a way to fake this.
361
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)
362
return nullptr;
363
364
// HeapReAlloc and HeapAlloc both happily accept 0 sized allocations.
365
// passing a 0 size into asan_realloc will free the allocation.
366
// To avoid this and keep behavior consistent, fudge the size if 0.
367
// (asan_malloc already does this)
368
if (dwBytes == 0)
369
dwBytes = 1;
370
371
size_t old_size;
372
if (dwFlags & HEAP_ZERO_MEMORY)
373
old_size = asan_malloc_usable_size(lpMem, pc, bp);
374
375
void *ptr = asan_realloc(lpMem, dwBytes, &stack);
376
if (ptr == nullptr)
377
return nullptr;
378
379
if (dwFlags & HEAP_ZERO_MEMORY) {
380
size_t new_size = asan_malloc_usable_size(ptr, pc, bp);
381
if (old_size < new_size)
382
REAL(memset)(((u8 *)ptr) + old_size, 0, new_size - old_size);
383
}
384
385
return ptr;
386
}
387
} // namespace __asan
388
389
INTERCEPTOR_WINAPI(LPVOID, HeapReAlloc, HANDLE hHeap, DWORD dwFlags,
390
LPVOID lpMem, size_t dwBytes) {
391
return SharedReAlloc(REAL(HeapReAlloc), (SizeFunction)REAL(HeapSize),
392
REAL(HeapFree), REAL(HeapAlloc), hHeap, dwFlags, lpMem,
393
dwBytes);
394
}
395
396
// The following functions are undocumented and subject to change.
397
// However, hooking them is necessary to hook Windows heap
398
// allocations with detours and their definitions are unlikely to change.
399
// Comments in /minkernel/ntos/rtl/heappublic.c indicate that these functions
400
// are part of the heap's public interface.
401
typedef unsigned long LOGICAL;
402
403
// This function is documented as part of the Driver Development Kit but *not*
404
// the Windows Development Kit.
405
LOGICAL RtlFreeHeap(void* HeapHandle, DWORD Flags,
406
void* BaseAddress);
407
408
// This function is documented as part of the Driver Development Kit but *not*
409
// the Windows Development Kit.
410
void* RtlAllocateHeap(void* HeapHandle, DWORD Flags, size_t Size);
411
412
// This function is completely undocumented.
413
void*
414
RtlReAllocateHeap(void* HeapHandle, DWORD Flags, void* BaseAddress,
415
size_t Size);
416
417
// This function is completely undocumented.
418
size_t RtlSizeHeap(void* HeapHandle, DWORD Flags, void* BaseAddress);
419
420
INTERCEPTOR_WINAPI(size_t, RtlSizeHeap, HANDLE HeapHandle, DWORD Flags,
421
void* BaseAddress) {
422
if (!flags()->windows_hook_rtl_allocators ||
423
UNLIKELY(!AsanInited() || OWNED_BY_RTL(HeapHandle, BaseAddress))) {
424
return REAL(RtlSizeHeap)(HeapHandle, Flags, BaseAddress);
425
}
426
GET_CURRENT_PC_BP_SP;
427
(void)sp;
428
return asan_malloc_usable_size(BaseAddress, pc, bp);
429
}
430
431
INTERCEPTOR_WINAPI(BOOL, RtlFreeHeap, HANDLE HeapHandle, DWORD Flags,
432
void* BaseAddress) {
433
// Heap allocations happen before this function is hooked, so we must fall
434
// back to the original function if the pointer is not from the ASAN heap, or
435
// unsupported flags are provided.
436
if (!flags()->windows_hook_rtl_allocators ||
437
UNLIKELY((HEAP_FREE_UNSUPPORTED_FLAGS & Flags) != 0 ||
438
OWNED_BY_RTL(HeapHandle, BaseAddress))) {
439
return REAL(RtlFreeHeap)(HeapHandle, Flags, BaseAddress);
440
}
441
GET_STACK_TRACE_FREE;
442
asan_free(BaseAddress, &stack, FROM_MALLOC);
443
return true;
444
}
445
446
INTERCEPTOR_WINAPI(void*, RtlAllocateHeap, HANDLE HeapHandle, DWORD Flags,
447
size_t Size) {
448
// If the ASAN runtime is not initialized, or we encounter an unsupported
449
// flag, fall back to the original allocator.
450
if (!flags()->windows_hook_rtl_allocators ||
451
UNLIKELY(!AsanInited() ||
452
(Flags & HEAP_ALLOCATE_UNSUPPORTED_FLAGS) != 0)) {
453
return REAL(RtlAllocateHeap)(HeapHandle, Flags, Size);
454
}
455
GET_STACK_TRACE_MALLOC;
456
void *p;
457
// Reading MSDN suggests that the *entire* usable allocation is zeroed out.
458
// Otherwise it is difficult to HeapReAlloc with HEAP_ZERO_MEMORY.
459
// https://blogs.msdn.microsoft.com/oldnewthing/20120316-00/?p=8083
460
if (Flags & HEAP_ZERO_MEMORY) {
461
p = asan_calloc(Size, 1, &stack);
462
} else {
463
p = asan_malloc(Size, &stack);
464
}
465
return p;
466
}
467
468
INTERCEPTOR_WINAPI(void*, RtlReAllocateHeap, HANDLE HeapHandle, DWORD Flags,
469
void* BaseAddress, size_t Size) {
470
// If it's actually a heap block which was allocated before the ASAN runtime
471
// came up, use the real RtlFreeHeap function.
472
if (!flags()->windows_hook_rtl_allocators)
473
return REAL(RtlReAllocateHeap)(HeapHandle, Flags, BaseAddress, Size);
474
475
return SharedReAlloc(REAL(RtlReAllocateHeap), REAL(RtlSizeHeap),
476
REAL(RtlFreeHeap), REAL(RtlAllocateHeap), HeapHandle,
477
Flags, BaseAddress, Size);
478
}
479
480
namespace __asan {
481
482
static void TryToOverrideFunction(const char *fname, uptr new_func) {
483
// Failure here is not fatal. The CRT may not be present, and different CRT
484
// versions use different symbols.
485
if (!__interception::OverrideFunction(fname, new_func))
486
VPrintf(2, "Failed to override function %s\n", fname);
487
}
488
489
void ReplaceSystemMalloc() {
490
#if defined(ASAN_DYNAMIC)
491
TryToOverrideFunction("free", (uptr)free);
492
TryToOverrideFunction("_free_base", (uptr)free);
493
TryToOverrideFunction("malloc", (uptr)malloc);
494
TryToOverrideFunction("_malloc_base", (uptr)malloc);
495
TryToOverrideFunction("_malloc_crt", (uptr)malloc);
496
TryToOverrideFunction("calloc", (uptr)calloc);
497
TryToOverrideFunction("_calloc_base", (uptr)calloc);
498
TryToOverrideFunction("_calloc_crt", (uptr)calloc);
499
TryToOverrideFunction("realloc", (uptr)realloc);
500
TryToOverrideFunction("_realloc_base", (uptr)realloc);
501
TryToOverrideFunction("_realloc_crt", (uptr)realloc);
502
TryToOverrideFunction("_recalloc", (uptr)_recalloc);
503
TryToOverrideFunction("_recalloc_base", (uptr)_recalloc);
504
TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc);
505
TryToOverrideFunction("_msize", (uptr)_msize);
506
TryToOverrideFunction("_msize_base", (uptr)_msize);
507
TryToOverrideFunction("_expand", (uptr)_expand);
508
TryToOverrideFunction("_expand_base", (uptr)_expand);
509
510
if (flags()->windows_hook_rtl_allocators) {
511
ASAN_INTERCEPT_FUNC(HeapSize);
512
ASAN_INTERCEPT_FUNC(HeapFree);
513
ASAN_INTERCEPT_FUNC(HeapReAlloc);
514
ASAN_INTERCEPT_FUNC(HeapAlloc);
515
516
// Undocumented functions must be intercepted by name, not by symbol.
517
__interception::OverrideFunction("RtlSizeHeap", (uptr)WRAP(RtlSizeHeap),
518
(uptr *)&REAL(RtlSizeHeap));
519
__interception::OverrideFunction("RtlFreeHeap", (uptr)WRAP(RtlFreeHeap),
520
(uptr *)&REAL(RtlFreeHeap));
521
__interception::OverrideFunction("RtlReAllocateHeap",
522
(uptr)WRAP(RtlReAllocateHeap),
523
(uptr *)&REAL(RtlReAllocateHeap));
524
__interception::OverrideFunction("RtlAllocateHeap",
525
(uptr)WRAP(RtlAllocateHeap),
526
(uptr *)&REAL(RtlAllocateHeap));
527
} else {
528
#define INTERCEPT_UCRT_FUNCTION(func) \
529
if (!INTERCEPT_FUNCTION_DLLIMPORT( \
530
"ucrtbase.dll", "api-ms-win-core-heap-l1-1-0.dll", func)) { \
531
VPrintf(2, "Failed to intercept ucrtbase.dll import %s\n", #func); \
532
}
533
INTERCEPT_UCRT_FUNCTION(HeapAlloc);
534
INTERCEPT_UCRT_FUNCTION(HeapFree);
535
INTERCEPT_UCRT_FUNCTION(HeapReAlloc);
536
INTERCEPT_UCRT_FUNCTION(HeapSize);
537
#undef INTERCEPT_UCRT_FUNCTION
538
}
539
// Recent versions of ucrtbase.dll appear to be built with PGO and LTCG, which
540
// enable cross-module inlining. This means our _malloc_base hook won't catch
541
// all CRT allocations. This code here patches the import table of
542
// ucrtbase.dll so that all attempts to use the lower-level win32 heap
543
// allocation API will be directed to ASan's heap. We don't currently
544
// intercept all calls to HeapAlloc. If we did, we would have to check on
545
// HeapFree whether the pointer came from ASan of from the system.
546
547
#endif // defined(ASAN_DYNAMIC)
548
}
549
} // namespace __asan
550
551
#endif // _WIN32
552
553