1//===-- hwasan_new_delete.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 HWAddressSanitizer.
10//
11// Interceptors for operators new and delete.
12//===----------------------------------------------------------------------===//
13
14#include "hwasan.h"
15#include "interception/interception.h"
16#include "sanitizer_common/sanitizer_allocator.h"
17#include "sanitizer_common/sanitizer_allocator_report.h"
18
19#include <stddef.h>
20#include <stdlib.h>
21
22#if HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE
23
24// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
25# define OPERATOR_NEW_BODY \
26 GET_MALLOC_STACK_TRACE; \
27 void *res = hwasan_malloc(size, &stack); \
28 if (UNLIKELY(!res)) \
29 ReportOutOfMemory(size, &stack); \
30 return res
31# define OPERATOR_NEW_BODY_NOTHROW \
32 GET_MALLOC_STACK_TRACE; \
33 return hwasan_malloc(size, &stack)
34# define OPERATOR_NEW_BODY_ARRAY \
35 GET_MALLOC_STACK_TRACE; \
36 void *res = hwasan_malloc(size, &stack); \
37 if (UNLIKELY(!res)) \
38 ReportOutOfMemory(size, &stack); \
39 return res
40# define OPERATOR_NEW_BODY_ARRAY_NOTHROW \
41 GET_MALLOC_STACK_TRACE; \
42 return hwasan_malloc(size, &stack)
43# define OPERATOR_NEW_BODY_ALIGN \
44 GET_MALLOC_STACK_TRACE; \
45 void *res = hwasan_memalign(static_cast<uptr>(align), size, &stack); \
46 if (UNLIKELY(!res)) \
47 ReportOutOfMemory(size, &stack); \
48 return res
49# define OPERATOR_NEW_BODY_ALIGN_NOTHROW \
50 GET_MALLOC_STACK_TRACE; \
51 return hwasan_memalign(static_cast<uptr>(align), size, &stack)
52# define OPERATOR_NEW_BODY_ALIGN_ARRAY \
53 GET_MALLOC_STACK_TRACE; \
54 void *res = hwasan_memalign(static_cast<uptr>(align), size, &stack); \
55 if (UNLIKELY(!res)) \
56 ReportOutOfMemory(size, &stack); \
57 return res
58# define OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW \
59 GET_MALLOC_STACK_TRACE; \
60 return hwasan_memalign(static_cast<uptr>(align), size, &stack)
61
62# define OPERATOR_DELETE_BODY \
63 GET_MALLOC_STACK_TRACE; \
64 if (ptr) \
65 hwasan_free(ptr, &stack)
66# define OPERATOR_DELETE_BODY_ARRAY \
67 GET_MALLOC_STACK_TRACE; \
68 if (ptr) \
69 hwasan_free(ptr, &stack)
70# define OPERATOR_DELETE_BODY_ALIGN \
71 GET_MALLOC_STACK_TRACE; \
72 if (ptr) \
73 hwasan_free(ptr, &stack)
74# define OPERATOR_DELETE_BODY_ALIGN_ARRAY \
75 GET_MALLOC_STACK_TRACE; \
76 if (ptr) \
77 hwasan_free(ptr, &stack)
78# define OPERATOR_DELETE_BODY_SIZE \
79 GET_MALLOC_STACK_TRACE; \
80 if (ptr) \
81 hwasan_free(ptr, &stack)
82# define OPERATOR_DELETE_BODY_SIZE_ARRAY \
83 GET_MALLOC_STACK_TRACE; \
84 if (ptr) \
85 hwasan_free(ptr, &stack)
86# define OPERATOR_DELETE_BODY_SIZE_ALIGN \
87 GET_MALLOC_STACK_TRACE; \
88 if (ptr) \
89 hwasan_free(ptr, &stack)
90# define OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY \
91 GET_MALLOC_STACK_TRACE; \
92 if (ptr) \
93 hwasan_free(ptr, &stack)
94
95#elif defined(__ANDROID__)
96
97// We don't actually want to intercept operator new and delete on Android, but
98// since we previously released a runtime that intercepted these functions,
99// removing the interceptors would break ABI. Therefore we simply forward to
100// malloc and free.
101# define OPERATOR_NEW_BODY return malloc(size)
102# define OPERATOR_NEW_BODY_NOTHROW return malloc(size)
103# define OPERATOR_NEW_BODY_ARRAY return malloc(size)
104# define OPERATOR_NEW_BODY_ARRAY_NOTHROW return malloc(size)
105# define OPERATOR_DELETE_BODY free(ptr)
106# define OPERATOR_DELETE_BODY_ARRAY free(ptr)
107# define OPERATOR_DELETE_BODY_SIZE free(ptr)
108# define OPERATOR_DELETE_BODY_SIZE_ARRAY free(ptr)
109
110#endif
111
112#ifdef OPERATOR_NEW_BODY
113
114using namespace __hwasan;
115
116// Fake std::nothrow_t to avoid including <new>.
117namespace std {
118struct nothrow_t {};
119} // namespace std
120
121INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(size_t size) {
122 OPERATOR_NEW_BODY;
123}
124INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
125 size_t size) {
126 OPERATOR_NEW_BODY_ARRAY;
127}
128INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
129 size_t size, std::nothrow_t const &) {
130 OPERATOR_NEW_BODY_NOTHROW;
131}
132INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
133 size_t size, std::nothrow_t const &) {
134 OPERATOR_NEW_BODY_ARRAY_NOTHROW;
135}
136
137INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
138 void *ptr) NOEXCEPT {
139 OPERATOR_DELETE_BODY;
140}
141INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
142 void *ptr) NOEXCEPT {
143 OPERATOR_DELETE_BODY_ARRAY;
144}
145INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
146 void *ptr, std::nothrow_t const &) {
147 OPERATOR_DELETE_BODY;
148}
149INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
150 void *ptr, std::nothrow_t const &) {
151 OPERATOR_DELETE_BODY_ARRAY;
152}
153INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
154 void *ptr, size_t) NOEXCEPT {
155 OPERATOR_DELETE_BODY_SIZE;
156}
157INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
158 void *ptr, size_t) NOEXCEPT {
159 OPERATOR_DELETE_BODY_SIZE_ARRAY;
160}
161
162#endif // OPERATOR_NEW_BODY
163
164#ifdef OPERATOR_NEW_BODY_ALIGN
165
166namespace std {
167enum class align_val_t : size_t {};
168} // namespace std
169
170INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
171 size_t size, std::align_val_t align) {
172 OPERATOR_NEW_BODY_ALIGN;
173}
174INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
175 size_t size, std::align_val_t align) {
176 OPERATOR_NEW_BODY_ALIGN_ARRAY;
177}
178INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
179 size_t size, std::align_val_t align, std::nothrow_t const &) {
180 OPERATOR_NEW_BODY_ALIGN_NOTHROW;
181}
182INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
183 size_t size, std::align_val_t align, std::nothrow_t const &) {
184 OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW;
185}
186
187INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
188 void *ptr, std::align_val_t align) NOEXCEPT {
189 OPERATOR_DELETE_BODY_ALIGN;
190}
191INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
192 void *ptr, std::align_val_t) NOEXCEPT {
193 OPERATOR_DELETE_BODY_ALIGN_ARRAY;
194}
195INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
196 void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
197 OPERATOR_DELETE_BODY_ALIGN;
198}
199INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
200 void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
201 OPERATOR_DELETE_BODY_ALIGN_ARRAY;
202}
203INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
204 void *ptr, size_t, std::align_val_t) NOEXCEPT {
205 OPERATOR_DELETE_BODY_SIZE_ALIGN;
206}
207INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
208 void *ptr, size_t, std::align_val_t) NOEXCEPT {
209 OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY;
210}
211INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
212 void *ptr, size_t, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
213 OPERATOR_DELETE_BODY_SIZE_ALIGN;
214}
215INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
216 void *ptr, size_t, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
217 OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY;
218}
219
220#endif // OPERATOR_NEW_BODY_ALIGN
221