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 "sanitizer_common/sanitizer_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_CURRENT_PC_BP_SP;
102  (void)sp;
103  return asan_malloc_usable_size(ptr, pc, bp);
104}
105
106SANITIZER_INTERFACE_ATTRIBUTE
107void *_expand(void *memblock, size_t size) {
108  // _expand is used in realloc-like functions to resize the buffer if possible.
109  // We don't want memory to stand still while resizing buffers, so return 0.
110  return 0;
111}
112
113SANITIZER_INTERFACE_ATTRIBUTE
114void *_expand_dbg(void *memblock, size_t size) {
115  return 0;
116}
117
118// TODO(timurrrr): Might want to add support for _aligned_* allocation
119// functions to detect a bit more bugs.  Those functions seem to wrap malloc().
120
121int _CrtDbgReport(int, const char*, int,
122                  const char*, const char*, ...) {
123  ShowStatsAndAbort();
124}
125
126int _CrtDbgReportW(int reportType, const wchar_t*, int,
127                   const wchar_t*, const wchar_t*, ...) {
128  ShowStatsAndAbort();
129}
130
131int _CrtSetReportMode(int, int) {
132  return 0;
133}
134}  // extern "C"
135
136using __interception::GetRealFunctionAddress;
137
138// We don't want to include "windows.h" in this file to avoid extra attributes
139// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
140extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
141                                        DWORD prot, DWORD *old_prot);
142const int PAGE_EXECUTE_READWRITE = 0x40;
143
144namespace __asan {
145void ReplaceSystemMalloc() {
146#if defined(_DLL)
147# ifdef _WIN64
148#  error ReplaceSystemMalloc was not tested on x64
149# endif
150  char *crt_malloc;
151  if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
152    // Replace malloc in the CRT dll with a jump to our malloc.
153    DWORD old_prot, unused;
154    CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
155    REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16);  // just in case.
156
157    ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
158    crt_malloc[0] = 0xE9;  // jmp, should be followed by an offset.
159    REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
160
161    CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
162
163    // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
164  }
165
166  // FIXME: investigate whether anything else is needed.
167#endif
168}
169}  // namespace __asan
170
171#endif  // _WIN32
172