asan_malloc_win.cc revision 3f4c3875c42078e22c7e5356c5746fd18756d958
1//===-- asan_malloc_win.cc --------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Windows-specific malloc interception.
13//===----------------------------------------------------------------------===//
14#ifdef _WIN32
15
16#include "asan_allocator.h"
17#include "asan_interceptors.h"
18#include "asan_internal.h"
19#include "asan_stack.h"
20
21#include "interception/interception.h"
22
23// ---------------------- Replacement functions ---------------- {{{1
24using namespace __asan;  // NOLINT
25
26// FIXME: Simply defining functions with the same signature in *.obj
27// files overrides the standard functions in *.lib
28// This works well for simple helloworld-like tests but might need to be
29// revisited in the future.
30
31extern "C" {
32void free(void *ptr) {
33  GET_STACK_TRACE_HERE_FOR_FREE(ptr);
34  return asan_free(ptr, &stack);
35}
36
37void _free_dbg(void* ptr, int) {
38  free(ptr);
39}
40
41void cfree(void *ptr) {
42  CHECK(!"cfree() should not be used on Windows?");
43}
44
45void *malloc(size_t size) {
46  GET_STACK_TRACE_HERE_FOR_MALLOC;
47  return asan_malloc(size, &stack);
48}
49
50void* _malloc_dbg(size_t size, int , const char*, int) {
51  return malloc(size);
52}
53
54void *calloc(size_t nmemb, size_t size) {
55  GET_STACK_TRACE_HERE_FOR_MALLOC;
56  return asan_calloc(nmemb, size, &stack);
57}
58
59void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
60  return calloc(n, size);
61}
62
63void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
64  return calloc(nmemb, size);
65}
66
67void *realloc(void *ptr, size_t size) {
68  GET_STACK_TRACE_HERE_FOR_MALLOC;
69  return asan_realloc(ptr, size, &stack);
70}
71
72void *_realloc_dbg(void *ptr, size_t size, int) {
73  CHECK(!"_realloc_dbg should not exist!");
74  return 0;
75}
76
77void* _recalloc(void* p, size_t n, size_t elem_size) {
78  if (!p)
79    return calloc(n, elem_size);
80  const size_t size = n * elem_size;
81  if (elem_size != 0 && size / elem_size != n)
82    return 0;
83  return realloc(p, size);
84}
85
86size_t _msize(void *ptr) {
87  GET_STACK_TRACE_HERE_FOR_MALLOC;
88  return asan_malloc_usable_size(ptr, &stack);
89}
90
91int _CrtDbgReport(int, const char*, int,
92                  const char*, const char*, ...) {
93  ShowStatsAndAbort();
94}
95
96int _CrtDbgReportW(int reportType, const wchar_t*, int,
97                   const wchar_t*, const wchar_t*, ...) {
98  ShowStatsAndAbort();
99}
100
101int _CrtSetReportMode(int, int) {
102  return 0;
103}
104}  // extern "C"
105
106using __interception::GetRealFunctionAddress;
107
108// We don't want to include "windows.h" in this file to avoid extra attributes
109// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
110extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
111                                        DWORD prot, DWORD *old_prot);
112const int PAGE_EXECUTE_READWRITE = 0x40;
113
114namespace __asan {
115void ReplaceSystemMalloc() {
116#if defined(_DLL)
117# ifdef _WIN64
118#  error ReplaceSystemMalloc was not tested on x64
119# endif
120  char *crt_malloc;
121  if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
122    // Replace malloc in the CRT dll with a jump to our malloc.
123    DWORD old_prot, unused;
124    CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
125    REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16);  // just in case.
126
127    ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
128    crt_malloc[0] = 0xE9;  // jmp, should be followed by an offset.
129    REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
130
131    CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
132
133    // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
134  }
135
136  // FIXME: investigate whether anything else is needed.
137#endif
138}
139}  // namespace __asan
140
141#endif  // _WIN32
142