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
26using namespace __asan;  // NOLINT
27
28// MT: Simply defining functions with the same signature in *.obj
29// files overrides the standard functions in the CRT.
30// MD: Memory allocation functions are defined in the CRT .dll,
31// so we have to intercept them before they are called for the first time.
32
33#if ASAN_DYNAMIC
34# define ALLOCATION_FUNCTION_ATTRIBUTE
35#else
36# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
37#endif
38
39extern "C" {
40ALLOCATION_FUNCTION_ATTRIBUTE
41void free(void *ptr) {
42  GET_STACK_TRACE_FREE;
43  return asan_free(ptr, &stack, FROM_MALLOC);
44}
45
46ALLOCATION_FUNCTION_ATTRIBUTE
47void _free_dbg(void *ptr, int) {
48  free(ptr);
49}
50
51ALLOCATION_FUNCTION_ATTRIBUTE
52void cfree(void *ptr) {
53  CHECK(!"cfree() should not be used on Windows");
54}
55
56ALLOCATION_FUNCTION_ATTRIBUTE
57void *malloc(size_t size) {
58  GET_STACK_TRACE_MALLOC;
59  return asan_malloc(size, &stack);
60}
61
62ALLOCATION_FUNCTION_ATTRIBUTE
63void *_malloc_dbg(size_t size, int, const char *, int) {
64  return malloc(size);
65}
66
67ALLOCATION_FUNCTION_ATTRIBUTE
68void *calloc(size_t nmemb, size_t size) {
69  GET_STACK_TRACE_MALLOC;
70  return asan_calloc(nmemb, size, &stack);
71}
72
73ALLOCATION_FUNCTION_ATTRIBUTE
74void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
75  return calloc(nmemb, size);
76}
77
78ALLOCATION_FUNCTION_ATTRIBUTE
79void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
80  return calloc(nmemb, size);
81}
82
83ALLOCATION_FUNCTION_ATTRIBUTE
84void *realloc(void *ptr, size_t size) {
85  GET_STACK_TRACE_MALLOC;
86  return asan_realloc(ptr, size, &stack);
87}
88
89ALLOCATION_FUNCTION_ATTRIBUTE
90void *_realloc_dbg(void *ptr, size_t size, int) {
91  CHECK(!"_realloc_dbg should not exist!");
92  return 0;
93}
94
95ALLOCATION_FUNCTION_ATTRIBUTE
96void *_recalloc(void *p, size_t n, size_t elem_size) {
97  if (!p)
98    return calloc(n, elem_size);
99  const size_t size = n * elem_size;
100  if (elem_size != 0 && size / elem_size != n)
101    return 0;
102  return realloc(p, size);
103}
104
105ALLOCATION_FUNCTION_ATTRIBUTE
106size_t _msize(void *ptr) {
107  GET_CURRENT_PC_BP_SP;
108  (void)sp;
109  return asan_malloc_usable_size(ptr, pc, bp);
110}
111
112ALLOCATION_FUNCTION_ATTRIBUTE
113void *_expand(void *memblock, size_t size) {
114  // _expand is used in realloc-like functions to resize the buffer if possible.
115  // We don't want memory to stand still while resizing buffers, so return 0.
116  return 0;
117}
118
119ALLOCATION_FUNCTION_ATTRIBUTE
120void *_expand_dbg(void *memblock, size_t size) {
121  return _expand(memblock, size);
122}
123
124// TODO(timurrrr): Might want to add support for _aligned_* allocation
125// functions to detect a bit more bugs.  Those functions seem to wrap malloc().
126
127int _CrtDbgReport(int, const char*, int,
128                  const char*, const char*, ...) {
129  ShowStatsAndAbort();
130}
131
132int _CrtDbgReportW(int reportType, const wchar_t*, int,
133                   const wchar_t*, const wchar_t*, ...) {
134  ShowStatsAndAbort();
135}
136
137int _CrtSetReportMode(int, int) {
138  return 0;
139}
140}  // extern "C"
141
142namespace __asan {
143void ReplaceSystemMalloc() {
144#if defined(ASAN_DYNAMIC)
145  // We don't check the result because CRT might not be used in the process.
146  __interception::OverrideFunction("free", (uptr)free);
147  __interception::OverrideFunction("malloc", (uptr)malloc);
148  __interception::OverrideFunction("_malloc_crt", (uptr)malloc);
149  __interception::OverrideFunction("calloc", (uptr)calloc);
150  __interception::OverrideFunction("_calloc_crt", (uptr)calloc);
151  __interception::OverrideFunction("realloc", (uptr)realloc);
152  __interception::OverrideFunction("_realloc_crt", (uptr)realloc);
153  __interception::OverrideFunction("_recalloc", (uptr)_recalloc);
154  __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
155  __interception::OverrideFunction("_msize", (uptr)_msize);
156  __interception::OverrideFunction("_expand", (uptr)_expand);
157
158  // Override different versions of 'operator new' and 'operator delete'.
159  // No need to override the nothrow versions as they just wrap the throw
160  // versions.
161  // FIXME: Unfortunately, MSVC miscompiles the statements that take the
162  // addresses of the array versions of these operators,
163  // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
164  // We might want to try to work around this by [inline] assembly or compiling
165  // parts of the RTL with Clang.
166  void *(*op_new)(size_t sz) = operator new;
167  void (*op_delete)(void *p) = operator delete;
168  void *(*op_array_new)(size_t sz) = operator new[];
169  void (*op_array_delete)(void *p) = operator delete[];
170  __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
171  __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
172  __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
173  __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
174#endif
175}
176}  // namespace __asan
177
178#endif  // _WIN32
179