1//===-- asan_interceptors.cpp ---------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of AddressSanitizer, an address sanity checker.
10//
11// Interceptors for operators new and delete.
12//===----------------------------------------------------------------------===//
13
14#include <stddef.h>
15
16#include "asan_allocator.h"
17#include "asan_internal.h"
18#include "asan_report.h"
19#include "asan_stack.h"
20#include "interception/interception.h"
21#include "sanitizer_common/sanitizer_new_handler.h"
22
23// C++ operators can't have dllexport attributes on Windows. We export them
24// anyway by passing extra -export flags to the linker, which is exactly that
25// dllexport would normally do. We need to export them in order to make the
26// VS2015 dynamic CRT (MD) work.
27#if SANITIZER_WINDOWS && defined(_MSC_VER)
28# define CXX_OPERATOR_ATTRIBUTE
29# define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))
30# ifdef _WIN64
31COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new
32COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow
33COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete
34COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete
35COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[]
36COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[]
37# else
38COMMENT_EXPORT("??2@YAPAXI@Z") // operator new
39COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow
40COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete
41COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete
42COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[]
43COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
44# endif
45# undef COMMENT_EXPORT
46#else
47# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
48#endif
49
50using namespace __asan;
51
52// This code has issues on OSX.
53// See https://github.com/google/sanitizers/issues/131.
54
55// Plug ASan's stack tracing, OOM reporting, and allocation helpers into the
56// shared operator new framework.
57#define SANITIZER_NEW_STACK_TRACE GET_STACK_TRACE_MALLOC
58#define SANITIZER_NEW_REPORT_OOM(size) ReportOutOfMemory(size, &stack)
59#define SANITIZER_NEW(size) asan_new(size, &stack)
60#define SANITIZER_NEW_ARRAY(size) asan_new_array(size, &stack)
61#define SANITIZER_NEW_ALIGNED(size, align) \
62 asan_new_aligned(size, static_cast<uptr>(align), &stack)
63#define SANITIZER_NEW_ARRAY_ALIGNED(size, align) \
64 asan_new_array_aligned(size, static_cast<uptr>(align), &stack)
65#include "sanitizer_common/sanitizer_new_operators.inc"
66
67// On OS X it's not enough to just provide our own 'operator new' and
68// 'operator delete' implementations, because they're going to be in the
69// runtime dylib, and the main executable will depend on both the runtime
70// dylib and libstdc++, each of those'll have its implementation of new and
71// delete.
72// To make sure that C++ allocation/deallocation operators are overridden on
73// OS X we need to intercept them using their mangled names.
74#if !SANITIZER_APPLE
75CXX_OPERATOR_ATTRIBUTE
76void* operator new(size_t size) { OPERATOR_NEW_BODY; }
77CXX_OPERATOR_ATTRIBUTE
78void* operator new[](size_t size) { OPERATOR_NEW_BODY_ARRAY; }
79CXX_OPERATOR_ATTRIBUTE
80void* operator new(size_t size, std::nothrow_t const&) NOEXCEPT {
81 OPERATOR_NEW_BODY_NOTHROW;
82}
83CXX_OPERATOR_ATTRIBUTE
84void* operator new[](size_t size, std::nothrow_t const&) NOEXCEPT {
85 OPERATOR_NEW_BODY_ARRAY_NOTHROW;
86}
87CXX_OPERATOR_ATTRIBUTE
88void* operator new(size_t size, std::align_val_t align) {
89 OPERATOR_NEW_BODY_ALIGN;
90}
91CXX_OPERATOR_ATTRIBUTE
92void* operator new[](size_t size, std::align_val_t align) {
93 OPERATOR_NEW_BODY_ALIGN_ARRAY;
94}
95CXX_OPERATOR_ATTRIBUTE
96void* operator new(size_t size, std::align_val_t align,
97 std::nothrow_t const&) NOEXCEPT {
98 OPERATOR_NEW_BODY_ALIGN_NOTHROW;
99}
100CXX_OPERATOR_ATTRIBUTE
101void* operator new[](size_t size, std::align_val_t align,
102 std::nothrow_t const&) NOEXCEPT {
103 OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW;
104}
105
106#else // SANITIZER_APPLE
107INTERCEPTOR(void*, _Znwm, size_t size) { OPERATOR_NEW_BODY; }
108INTERCEPTOR(void*, _Znam, size_t size) { OPERATOR_NEW_BODY_ARRAY; }
109INTERCEPTOR(void*, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
110 OPERATOR_NEW_BODY_NOTHROW;
111}
112INTERCEPTOR(void*, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
113 OPERATOR_NEW_BODY_ARRAY_NOTHROW;
114}
115#endif // !SANITIZER_APPLE
116
117#define OPERATOR_DELETE_BODY \
118 GET_STACK_TRACE_FREE; \
119 asan_delete(ptr, &stack)
120#define OPERATOR_DELETE_BODY_ARRAY \
121 GET_STACK_TRACE_FREE; \
122 asan_delete_array(ptr, &stack)
123#define OPERATOR_DELETE_BODY_ALIGN \
124 GET_STACK_TRACE_FREE; \
125 asan_delete_aligned(ptr, static_cast<uptr>(align), &stack)
126#define OPERATOR_DELETE_BODY_ALIGN_ARRAY \
127 GET_STACK_TRACE_FREE; \
128 asan_delete_array_aligned(ptr, static_cast<uptr>(align), &stack)
129#define OPERATOR_DELETE_BODY_SIZE \
130 GET_STACK_TRACE_FREE; \
131 asan_delete_sized(ptr, size, &stack)
132#define OPERATOR_DELETE_BODY_SIZE_ARRAY \
133 GET_STACK_TRACE_FREE; \
134 asan_delete_array_sized(ptr, size, &stack)
135#define OPERATOR_DELETE_BODY_SIZE_ALIGN \
136 GET_STACK_TRACE_FREE; \
137 asan_delete_sized_aligned(ptr, size, static_cast<uptr>(align), &stack)
138#define OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY \
139 GET_STACK_TRACE_FREE; \
140 asan_delete_array_sized_aligned(ptr, size, static_cast<uptr>(align), &stack)
141
142#if !SANITIZER_APPLE
143CXX_OPERATOR_ATTRIBUTE
144void operator delete(void* ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
145CXX_OPERATOR_ATTRIBUTE
146void operator delete[](void* ptr) NOEXCEPT { OPERATOR_DELETE_BODY_ARRAY; }
147CXX_OPERATOR_ATTRIBUTE
148void operator delete(void* ptr, std::nothrow_t const&) NOEXCEPT {
149 OPERATOR_DELETE_BODY;
150}
151CXX_OPERATOR_ATTRIBUTE
152void operator delete[](void* ptr, std::nothrow_t const&) NOEXCEPT {
153 OPERATOR_DELETE_BODY_ARRAY;
154}
155CXX_OPERATOR_ATTRIBUTE
156void operator delete(void* ptr, size_t size) NOEXCEPT {
157 OPERATOR_DELETE_BODY_SIZE;
158}
159CXX_OPERATOR_ATTRIBUTE
160void operator delete[](void* ptr, size_t size) NOEXCEPT {
161 OPERATOR_DELETE_BODY_SIZE_ARRAY;
162}
163CXX_OPERATOR_ATTRIBUTE
164void operator delete(void* ptr, std::align_val_t align) NOEXCEPT {
165 OPERATOR_DELETE_BODY_ALIGN;
166}
167CXX_OPERATOR_ATTRIBUTE
168void operator delete[](void* ptr, std::align_val_t align) NOEXCEPT {
169 OPERATOR_DELETE_BODY_ALIGN_ARRAY;
170}
171CXX_OPERATOR_ATTRIBUTE
172void operator delete(void* ptr, std::align_val_t align,
173 std::nothrow_t const&) NOEXCEPT {
174 OPERATOR_DELETE_BODY_ALIGN;
175}
176CXX_OPERATOR_ATTRIBUTE
177void operator delete[](void* ptr, std::align_val_t align,
178 std::nothrow_t const&) NOEXCEPT {
179 OPERATOR_DELETE_BODY_ALIGN_ARRAY;
180}
181CXX_OPERATOR_ATTRIBUTE
182void operator delete(void* ptr, size_t size, std::align_val_t align) NOEXCEPT {
183 OPERATOR_DELETE_BODY_SIZE_ALIGN;
184}
185CXX_OPERATOR_ATTRIBUTE
186void operator delete[](void* ptr, size_t size,
187 std::align_val_t align) NOEXCEPT {
188 OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY;
189}
190
191#else // SANITIZER_APPLE
192INTERCEPTOR(void, _ZdlPv, void* ptr) { OPERATOR_DELETE_BODY; }
193INTERCEPTOR(void, _ZdaPv, void* ptr) { OPERATOR_DELETE_BODY_ARRAY; }
194INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void* ptr, std::nothrow_t const&) {
195 OPERATOR_DELETE_BODY;
196}
197INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void* ptr, std::nothrow_t const&) {
198 OPERATOR_DELETE_BODY_ARRAY;
199}
200#endif // !SANITIZER_APPLE
201