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