1//===-- asan_interceptors.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// Interceptors for operators new and delete.
13//===----------------------------------------------------------------------===//
14
15#include "asan_allocator.h"
16#include "asan_internal.h"
17#include "asan_malloc_local.h"
18#include "asan_report.h"
19#include "asan_stack.h"
20
21#include "interception/interception.h"
22
23#include <stddef.h>
24
25// C++ operators can't have dllexport attributes on Windows. We export them
26// anyway by passing extra -export flags to the linker, which is exactly that
27// dllexport would normally do. We need to export them in order to make the
28// VS2015 dynamic CRT (MD) work.
29#if SANITIZER_WINDOWS && defined(_MSC_VER)
30#define CXX_OPERATOR_ATTRIBUTE
31#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))
32#ifdef _WIN64
33COMMENT_EXPORT("??2@YAPEAX_K@Z")                     // operator new
34COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z")  // operator new nothrow
35COMMENT_EXPORT("??3@YAXPEAX@Z")                      // operator delete
36COMMENT_EXPORT("??3@YAXPEAX_K@Z")                    // sized operator delete
37COMMENT_EXPORT("??_U@YAPEAX_K@Z")                    // operator new[]
38COMMENT_EXPORT("??_V@YAXPEAX@Z")                     // operator delete[]
39#else
40COMMENT_EXPORT("??2@YAPAXI@Z")                    // operator new
41COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z")  // operator new nothrow
42COMMENT_EXPORT("??3@YAXPAX@Z")                    // operator delete
43COMMENT_EXPORT("??3@YAXPAXI@Z")                   // sized operator delete
44COMMENT_EXPORT("??_U@YAPAXI@Z")                   // operator new[]
45COMMENT_EXPORT("??_V@YAXPAX@Z")                   // operator delete[]
46#endif
47#undef COMMENT_EXPORT
48#else
49#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
50#endif
51
52using namespace __asan;  // NOLINT
53
54// FreeBSD prior v9.2 have wrong definition of 'size_t'.
55// http://svnweb.freebsd.org/base?view=revision&revision=232261
56#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
57#include <sys/param.h>
58#if __FreeBSD_version <= 902001  // v9.2
59#define size_t unsigned
60#endif  // __FreeBSD_version
61#endif  // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
62
63// This code has issues on OSX.
64// See https://github.com/google/sanitizers/issues/131.
65
66// Fake std::nothrow_t and std::align_val_t to avoid including <new>.
67namespace std {
68struct nothrow_t {};
69enum class align_val_t: size_t {};
70}  // namespace std
71
72// TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM.
73// For local pool allocation, align to SHADOW_GRANULARITY to match asan
74// allocator behavior.
75#define OPERATOR_NEW_BODY(type, nothrow) \
76  if (ALLOCATE_FROM_LOCAL_POOL) {\
77    void *res = MemalignFromLocalPool(SHADOW_GRANULARITY, size);\
78    if (!nothrow) CHECK(res);\
79    return res;\
80  }\
81  GET_STACK_TRACE_MALLOC;\
82  void *res = asan_memalign(0, size, &stack, type);\
83  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
84  return res;
85#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
86  if (ALLOCATE_FROM_LOCAL_POOL) {\
87    void *res = MemalignFromLocalPool((uptr)align, size);\
88    if (!nothrow) CHECK(res);\
89    return res;\
90  }\
91  GET_STACK_TRACE_MALLOC;\
92  void *res = asan_memalign((uptr)align, size, &stack, type);\
93  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
94  return res;
95
96// On OS X it's not enough to just provide our own 'operator new' and
97// 'operator delete' implementations, because they're going to be in the
98// runtime dylib, and the main executable will depend on both the runtime
99// dylib and libstdc++, each of those'll have its implementation of new and
100// delete.
101// To make sure that C++ allocation/deallocation operators are overridden on
102// OS X we need to intercept them using their mangled names.
103#if !SANITIZER_MAC
104CXX_OPERATOR_ATTRIBUTE
105void *operator new(size_t size)
106{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); }
107CXX_OPERATOR_ATTRIBUTE
108void *operator new[](size_t size)
109{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); }
110CXX_OPERATOR_ATTRIBUTE
111void *operator new(size_t size, std::nothrow_t const&)
112{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); }
113CXX_OPERATOR_ATTRIBUTE
114void *operator new[](size_t size, std::nothrow_t const&)
115{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); }
116CXX_OPERATOR_ATTRIBUTE
117void *operator new(size_t size, std::align_val_t align)
118{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); }
119CXX_OPERATOR_ATTRIBUTE
120void *operator new[](size_t size, std::align_val_t align)
121{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); }
122CXX_OPERATOR_ATTRIBUTE
123void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
124{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); }
125CXX_OPERATOR_ATTRIBUTE
126void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
127{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); }
128
129#else  // SANITIZER_MAC
130INTERCEPTOR(void *, _Znwm, size_t size) {
131  OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
132}
133INTERCEPTOR(void *, _Znam, size_t size) {
134  OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
135}
136INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
137  OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
138}
139INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
140  OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
141}
142#endif  // !SANITIZER_MAC
143
144#define OPERATOR_DELETE_BODY(type) \
145  if (IS_FROM_LOCAL_POOL(ptr)) return;\
146  GET_STACK_TRACE_FREE;\
147  asan_delete(ptr, 0, 0, &stack, type);
148
149#define OPERATOR_DELETE_BODY_SIZE(type) \
150  if (IS_FROM_LOCAL_POOL(ptr)) return;\
151  GET_STACK_TRACE_FREE;\
152  asan_delete(ptr, size, 0, &stack, type);
153
154#define OPERATOR_DELETE_BODY_ALIGN(type) \
155  if (IS_FROM_LOCAL_POOL(ptr)) return;\
156  GET_STACK_TRACE_FREE;\
157  asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type);
158
159#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \
160  if (IS_FROM_LOCAL_POOL(ptr)) return;\
161  GET_STACK_TRACE_FREE;\
162  asan_delete(ptr, size, static_cast<uptr>(align), &stack, type);
163
164#if !SANITIZER_MAC
165CXX_OPERATOR_ATTRIBUTE
166void operator delete(void *ptr) NOEXCEPT
167{ OPERATOR_DELETE_BODY(FROM_NEW); }
168CXX_OPERATOR_ATTRIBUTE
169void operator delete[](void *ptr) NOEXCEPT
170{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
171CXX_OPERATOR_ATTRIBUTE
172void operator delete(void *ptr, std::nothrow_t const&)
173{ OPERATOR_DELETE_BODY(FROM_NEW); }
174CXX_OPERATOR_ATTRIBUTE
175void operator delete[](void *ptr, std::nothrow_t const&)
176{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
177CXX_OPERATOR_ATTRIBUTE
178void operator delete(void *ptr, size_t size) NOEXCEPT
179{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW); }
180CXX_OPERATOR_ATTRIBUTE
181void operator delete[](void *ptr, size_t size) NOEXCEPT
182{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); }
183CXX_OPERATOR_ATTRIBUTE
184void operator delete(void *ptr, std::align_val_t align) NOEXCEPT
185{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
186CXX_OPERATOR_ATTRIBUTE
187void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT
188{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
189CXX_OPERATOR_ATTRIBUTE
190void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&)
191{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
192CXX_OPERATOR_ATTRIBUTE
193void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&)
194{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
195CXX_OPERATOR_ATTRIBUTE
196void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT
197{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); }
198CXX_OPERATOR_ATTRIBUTE
199void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT
200{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); }
201
202#else  // SANITIZER_MAC
203INTERCEPTOR(void, _ZdlPv, void *ptr)
204{ OPERATOR_DELETE_BODY(FROM_NEW); }
205INTERCEPTOR(void, _ZdaPv, void *ptr)
206{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
207INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
208{ OPERATOR_DELETE_BODY(FROM_NEW); }
209INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
210{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
211#endif  // !SANITIZER_MAC
212