1353944Sdim//===-- asan_interceptors.cpp ---------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker.
10353944Sdim//
11353944Sdim// Interceptors for operators new and delete.
12353944Sdim//===----------------------------------------------------------------------===//
13353944Sdim
14353944Sdim#include "asan_allocator.h"
15353944Sdim#include "asan_internal.h"
16353944Sdim#include "asan_malloc_local.h"
17353944Sdim#include "asan_report.h"
18353944Sdim#include "asan_stack.h"
19353944Sdim
20353944Sdim#include "interception/interception.h"
21353944Sdim
22353944Sdim#include <stddef.h>
23353944Sdim
24353944Sdim// C++ operators can't have dllexport attributes on Windows. We export them
25353944Sdim// anyway by passing extra -export flags to the linker, which is exactly that
26353944Sdim// dllexport would normally do. We need to export them in order to make the
27353944Sdim// VS2015 dynamic CRT (MD) work.
28353944Sdim#if SANITIZER_WINDOWS && defined(_MSC_VER)
29353944Sdim#define CXX_OPERATOR_ATTRIBUTE
30353944Sdim#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))
31353944Sdim#ifdef _WIN64
32353944SdimCOMMENT_EXPORT("??2@YAPEAX_K@Z")                     // operator new
33353944SdimCOMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z")  // operator new nothrow
34353944SdimCOMMENT_EXPORT("??3@YAXPEAX@Z")                      // operator delete
35353944SdimCOMMENT_EXPORT("??3@YAXPEAX_K@Z")                    // sized operator delete
36353944SdimCOMMENT_EXPORT("??_U@YAPEAX_K@Z")                    // operator new[]
37353944SdimCOMMENT_EXPORT("??_V@YAXPEAX@Z")                     // operator delete[]
38353944Sdim#else
39353944SdimCOMMENT_EXPORT("??2@YAPAXI@Z")                    // operator new
40353944SdimCOMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z")  // operator new nothrow
41353944SdimCOMMENT_EXPORT("??3@YAXPAX@Z")                    // operator delete
42353944SdimCOMMENT_EXPORT("??3@YAXPAXI@Z")                   // sized operator delete
43353944SdimCOMMENT_EXPORT("??_U@YAPAXI@Z")                   // operator new[]
44353944SdimCOMMENT_EXPORT("??_V@YAXPAX@Z")                   // operator delete[]
45353944Sdim#endif
46353944Sdim#undef COMMENT_EXPORT
47353944Sdim#else
48353944Sdim#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
49353944Sdim#endif
50353944Sdim
51353944Sdimusing namespace __asan;
52353944Sdim
53353944Sdim// FreeBSD prior v9.2 have wrong definition of 'size_t'.
54353944Sdim// http://svnweb.freebsd.org/base?view=revision&revision=232261
55353944Sdim#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
56353944Sdim#include <sys/param.h>
57353944Sdim#if __FreeBSD_version <= 902001  // v9.2
58353944Sdim#define size_t unsigned
59353944Sdim#endif  // __FreeBSD_version
60353944Sdim#endif  // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
61353944Sdim
62353944Sdim// This code has issues on OSX.
63353944Sdim// See https://github.com/google/sanitizers/issues/131.
64353944Sdim
65353944Sdim// Fake std::nothrow_t and std::align_val_t to avoid including <new>.
66353944Sdimnamespace std {
67353944Sdimstruct nothrow_t {};
68353944Sdimenum class align_val_t: size_t {};
69353944Sdim}  // namespace std
70353944Sdim
71353944Sdim// TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM.
72353944Sdim// For local pool allocation, align to SHADOW_GRANULARITY to match asan
73353944Sdim// allocator behavior.
74353944Sdim#define OPERATOR_NEW_BODY(type, nothrow)            \
75353944Sdim  MAYBE_ALLOCATE_FROM_LOCAL_POOL(nothrow);          \
76353944Sdim  GET_STACK_TRACE_MALLOC;                           \
77353944Sdim  void *res = asan_memalign(0, size, &stack, type); \
78353944Sdim  if (!nothrow && UNLIKELY(!res))                   \
79353944Sdim    ReportOutOfMemory(size, &stack);                \
80353944Sdim  return res;
81353944Sdim#define OPERATOR_NEW_BODY_ALIGN(type, nothrow)                \
82353944Sdim  MAYBE_ALLOCATE_FROM_LOCAL_POOL(nothrow);                    \
83353944Sdim  GET_STACK_TRACE_MALLOC;                                     \
84353944Sdim  void *res = asan_memalign((uptr)align, size, &stack, type); \
85353944Sdim  if (!nothrow && UNLIKELY(!res))                             \
86353944Sdim    ReportOutOfMemory(size, &stack);                          \
87353944Sdim  return res;
88353944Sdim
89353944Sdim// On OS X it's not enough to just provide our own 'operator new' and
90353944Sdim// 'operator delete' implementations, because they're going to be in the
91353944Sdim// runtime dylib, and the main executable will depend on both the runtime
92353944Sdim// dylib and libstdc++, each of those'll have its implementation of new and
93353944Sdim// delete.
94353944Sdim// To make sure that C++ allocation/deallocation operators are overridden on
95353944Sdim// OS X we need to intercept them using their mangled names.
96353944Sdim#if !SANITIZER_MAC
97353944SdimCXX_OPERATOR_ATTRIBUTE
98353944Sdimvoid *operator new(size_t size)
99353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); }
100353944SdimCXX_OPERATOR_ATTRIBUTE
101353944Sdimvoid *operator new[](size_t size)
102353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); }
103353944SdimCXX_OPERATOR_ATTRIBUTE
104353944Sdimvoid *operator new(size_t size, std::nothrow_t const&)
105353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); }
106353944SdimCXX_OPERATOR_ATTRIBUTE
107353944Sdimvoid *operator new[](size_t size, std::nothrow_t const&)
108353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); }
109353944SdimCXX_OPERATOR_ATTRIBUTE
110353944Sdimvoid *operator new(size_t size, std::align_val_t align)
111353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); }
112353944SdimCXX_OPERATOR_ATTRIBUTE
113353944Sdimvoid *operator new[](size_t size, std::align_val_t align)
114353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); }
115353944SdimCXX_OPERATOR_ATTRIBUTE
116353944Sdimvoid *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
117353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); }
118353944SdimCXX_OPERATOR_ATTRIBUTE
119353944Sdimvoid *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
120353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); }
121353944Sdim
122353944Sdim#else  // SANITIZER_MAC
123353944SdimINTERCEPTOR(void *, _Znwm, size_t size) {
124353944Sdim  OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
125353944Sdim}
126353944SdimINTERCEPTOR(void *, _Znam, size_t size) {
127353944Sdim  OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
128353944Sdim}
129353944SdimINTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
130353944Sdim  OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
131353944Sdim}
132353944SdimINTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
133353944Sdim  OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
134353944Sdim}
135353944Sdim#endif  // !SANITIZER_MAC
136353944Sdim
137353944Sdim#define OPERATOR_DELETE_BODY(type) \
138353944Sdim  if (IS_FROM_LOCAL_POOL(ptr)) return;\
139353944Sdim  GET_STACK_TRACE_FREE;\
140353944Sdim  asan_delete(ptr, 0, 0, &stack, type);
141353944Sdim
142353944Sdim#define OPERATOR_DELETE_BODY_SIZE(type) \
143353944Sdim  if (IS_FROM_LOCAL_POOL(ptr)) return;\
144353944Sdim  GET_STACK_TRACE_FREE;\
145353944Sdim  asan_delete(ptr, size, 0, &stack, type);
146353944Sdim
147353944Sdim#define OPERATOR_DELETE_BODY_ALIGN(type) \
148353944Sdim  if (IS_FROM_LOCAL_POOL(ptr)) return;\
149353944Sdim  GET_STACK_TRACE_FREE;\
150353944Sdim  asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type);
151353944Sdim
152353944Sdim#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \
153353944Sdim  if (IS_FROM_LOCAL_POOL(ptr)) return;\
154353944Sdim  GET_STACK_TRACE_FREE;\
155353944Sdim  asan_delete(ptr, size, static_cast<uptr>(align), &stack, type);
156353944Sdim
157353944Sdim#if !SANITIZER_MAC
158353944SdimCXX_OPERATOR_ATTRIBUTE
159353944Sdimvoid operator delete(void *ptr) NOEXCEPT
160353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); }
161353944SdimCXX_OPERATOR_ATTRIBUTE
162353944Sdimvoid operator delete[](void *ptr) NOEXCEPT
163353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
164353944SdimCXX_OPERATOR_ATTRIBUTE
165353944Sdimvoid operator delete(void *ptr, std::nothrow_t const&)
166353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); }
167353944SdimCXX_OPERATOR_ATTRIBUTE
168353944Sdimvoid operator delete[](void *ptr, std::nothrow_t const&)
169353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
170353944SdimCXX_OPERATOR_ATTRIBUTE
171353944Sdimvoid operator delete(void *ptr, size_t size) NOEXCEPT
172353944Sdim{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW); }
173353944SdimCXX_OPERATOR_ATTRIBUTE
174353944Sdimvoid operator delete[](void *ptr, size_t size) NOEXCEPT
175353944Sdim{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); }
176353944SdimCXX_OPERATOR_ATTRIBUTE
177353944Sdimvoid operator delete(void *ptr, std::align_val_t align) NOEXCEPT
178353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
179353944SdimCXX_OPERATOR_ATTRIBUTE
180353944Sdimvoid operator delete[](void *ptr, std::align_val_t align) NOEXCEPT
181353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
182353944SdimCXX_OPERATOR_ATTRIBUTE
183353944Sdimvoid operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&)
184353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
185353944SdimCXX_OPERATOR_ATTRIBUTE
186353944Sdimvoid operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&)
187353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
188353944SdimCXX_OPERATOR_ATTRIBUTE
189353944Sdimvoid operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT
190353944Sdim{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); }
191353944SdimCXX_OPERATOR_ATTRIBUTE
192353944Sdimvoid operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT
193353944Sdim{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); }
194353944Sdim
195353944Sdim#else  // SANITIZER_MAC
196353944SdimINTERCEPTOR(void, _ZdlPv, void *ptr)
197353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); }
198353944SdimINTERCEPTOR(void, _ZdaPv, void *ptr)
199353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
200353944SdimINTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
201353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); }
202353944SdimINTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
203353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
204353944Sdim#endif  // !SANITIZER_MAC
205