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