1e5f5895bda30f374b0b51412fd4d837fa59aed66Alexey Samsonov//===-- asan_malloc_win.cc ------------------------------------------------===// 2938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// 3938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// The LLVM Compiler Infrastructure 4938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// 5938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// This file is distributed under the University of Illinois Open Source 6938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// License. See LICENSE.TXT for details. 7938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// 8938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany//===----------------------------------------------------------------------===// 9938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// 10938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// This file is a part of AddressSanitizer, an address sanity checker. 11938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// 12938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// Windows-specific malloc interception. 13938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany//===----------------------------------------------------------------------===// 1424e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov 1524e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#include "sanitizer_common/sanitizer_platform.h" 1630e110edf92303237d471f1cb8e3ad07954fb145Evgeniy Stepanov#if SANITIZER_WINDOWS 17938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 18938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany#include "asan_allocator.h" 19938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany#include "asan_interceptors.h" 20938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany#include "asan_internal.h" 21938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany#include "asan_stack.h" 222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_interception.h" 23938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 24b46941a1d23012491a7a8a52718cacbde3c19ba1Alexey Samsonov#include <stddef.h> 25b46941a1d23012491a7a8a52718cacbde3c19ba1Alexey Samsonov 26938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// ---------------------- Replacement functions ---------------- {{{1 27938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryanyusing namespace __asan; // NOLINT 28938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 29938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// FIXME: Simply defining functions with the same signature in *.obj 30938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// files overrides the standard functions in *.lib 31938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// This works well for simple helloworld-like tests but might need to be 32938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany// revisited in the future. 33938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 34938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryanyextern "C" { 35e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 36938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryanyvoid free(void *ptr) { 37a30c8f9eac981dcf137e84226810b760e35c7be1Kostya Serebryany GET_STACK_TRACE_FREE; 38fe6d91684bcda766593800f6307233f1a33d31f6Kostya Serebryany return asan_free(ptr, &stack, FROM_MALLOC); 39938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany} 40938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 41e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 421bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovvoid _free_dbg(void* ptr, int) { 431bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov free(ptr); 441bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 451bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 461bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovvoid cfree(void *ptr) { 471bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov CHECK(!"cfree() should not be used on Windows?"); 481bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 491bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 50e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 51938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryanyvoid *malloc(size_t size) { 52a30c8f9eac981dcf137e84226810b760e35c7be1Kostya Serebryany GET_STACK_TRACE_MALLOC; 53938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany return asan_malloc(size, &stack); 54938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany} 55938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 56e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 571bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovvoid* _malloc_dbg(size_t size, int , const char*, int) { 581bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov return malloc(size); 591bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 601bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 61e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 62938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryanyvoid *calloc(size_t nmemb, size_t size) { 63a30c8f9eac981dcf137e84226810b760e35c7be1Kostya Serebryany GET_STACK_TRACE_MALLOC; 64938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany return asan_calloc(nmemb, size, &stack); 65938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany} 66938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 67e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 681bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovvoid* _calloc_dbg(size_t n, size_t size, int, const char*, int) { 691bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov return calloc(n, size); 701bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 711bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 72e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 732716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanovvoid *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) { 741bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov return calloc(nmemb, size); 752716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov} 762716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov 77e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 78938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryanyvoid *realloc(void *ptr, size_t size) { 79a30c8f9eac981dcf137e84226810b760e35c7be1Kostya Serebryany GET_STACK_TRACE_MALLOC; 80938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany return asan_realloc(ptr, size, &stack); 81938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany} 82cf13eb28b24109c0523275a62973412b702cbb43Timur Iskhodzhanov 83e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 841bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovvoid *_realloc_dbg(void *ptr, size_t size, int) { 851bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov CHECK(!"_realloc_dbg should not exist!"); 863f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany return 0; 871bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 881bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 89e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 901bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovvoid* _recalloc(void* p, size_t n, size_t elem_size) { 911bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov if (!p) 921bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov return calloc(n, elem_size); 931bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov const size_t size = n * elem_size; 941bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov if (elem_size != 0 && size / elem_size != n) 953f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany return 0; 961bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov return realloc(p, size); 971bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 981bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 99e274841d866cde3d393f643632bf67d59469430eTimur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE 100cf13eb28b24109c0523275a62973412b702cbb43Timur Iskhodzhanovsize_t _msize(void *ptr) { 1011b17f5b79d58c5aff291dde05727ad0b215b81c6Alexey Samsonov GET_CURRENT_PC_BP_SP; 1021b17f5b79d58c5aff291dde05727ad0b215b81c6Alexey Samsonov (void)sp; 1031b17f5b79d58c5aff291dde05727ad0b215b81c6Alexey Samsonov return asan_malloc_usable_size(ptr, pc, bp); 104cf13eb28b24109c0523275a62973412b702cbb43Timur Iskhodzhanov} 1051bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 1062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesSANITIZER_INTERFACE_ATTRIBUTE 1072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid *_expand(void *memblock, size_t size) { 1082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // _expand is used in realloc-like functions to resize the buffer if possible. 1092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // We don't want memory to stand still while resizing buffers, so return 0. 1102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return 0; 1112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 1122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesSANITIZER_INTERFACE_ATTRIBUTE 1142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid *_expand_dbg(void *memblock, size_t size) { 1152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return 0; 1162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 1172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// TODO(timurrrr): Might want to add support for _aligned_* allocation 1192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// functions to detect a bit more bugs. Those functions seem to wrap malloc(). 1202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1211bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovint _CrtDbgReport(int, const char*, int, 1221bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov const char*, const char*, ...) { 1231bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov ShowStatsAndAbort(); 1241bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 1251bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 1261bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovint _CrtDbgReportW(int reportType, const wchar_t*, int, 1271bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov const wchar_t*, const wchar_t*, ...) { 1281bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov ShowStatsAndAbort(); 1291bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 1301bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov 1311bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanovint _CrtSetReportMode(int, int) { 1321bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov return 0; 1331bbe2561a695af15f116e5ffec7e5f9cf7c54811Timur Iskhodzhanov} 134938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany} // extern "C" 135938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany 136d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanovusing __interception::GetRealFunctionAddress; 137d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov 138d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov// We don't want to include "windows.h" in this file to avoid extra attributes 139d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov// set on malloc/free etc (e.g. dllimport), so declare a few things manually: 140d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanovextern "C" int __stdcall VirtualProtect(void* addr, size_t size, 141d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov DWORD prot, DWORD *old_prot); 142d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanovconst int PAGE_EXECUTE_READWRITE = 0x40; 143d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov 144d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanovnamespace __asan { 145d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanovvoid ReplaceSystemMalloc() { 1462716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov#if defined(_DLL) 1472716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov# ifdef _WIN64 1482716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov# error ReplaceSystemMalloc was not tested on x64 1492716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov# endif 150d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov char *crt_malloc; 151d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) { 152d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov // Replace malloc in the CRT dll with a jump to our malloc. 153d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov DWORD old_prot, unused; 154d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot)); 155d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16); // just in case. 156d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov 1572716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5; 158d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov crt_malloc[0] = 0xE9; // jmp, should be followed by an offset. 159d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset)); 160d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov 161d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused)); 162d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov 163d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64. 164d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov } 165d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov 166d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov // FIXME: investigate whether anything else is needed. 1672716a61d085a8fdf13a099822720e320414cc4dcTimur Iskhodzhanov#endif 168d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov} 169d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov} // namespace __asan 170d9a88ccecbd7af0d11dae4d23d85706479470fdfTimur Iskhodzhanov 171938b105aaa1ebb08b1ddacb2944b3caa3524a5a5Kostya Serebryany#endif // _WIN32 172