asan_malloc_win.cpp 20 KB

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