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