1//===-- tsan_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 ThreadSanitizer (TSan), a race detector.
10//
11// Interceptors for operators new and delete.
12//===----------------------------------------------------------------------===//
13#include "interception/interception.h"
14#include "sanitizer_common/sanitizer_allocator.h"
15#include "sanitizer_common/sanitizer_allocator_checks.h"
16#include "sanitizer_common/sanitizer_allocator_report.h"
17#include "sanitizer_common/sanitizer_internal_defs.h"
18#include "tsan_interceptors.h"
19#include "tsan_rtl.h"
20
21using namespace __tsan;
22
23namespace std {
24struct nothrow_t {};
25enum class align_val_t: __sanitizer::uptr {};
26} // namespace std
27
28DECLARE_REAL(void *, malloc, uptr size)
29DECLARE_REAL(void, free, void *ptr)
30
31// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
32#define OPERATOR_NEW_BODY(mangled_name, nothrow) \
33 if (in_symbolizer()) \
34 return InternalAlloc(size); \
35 void *p = 0; \
36 { \
37 SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
38 p = user_alloc(thr, pc, size); \
39 if (!nothrow && UNLIKELY(!p)) { \
40 GET_STACK_TRACE_FATAL(thr, pc); \
41 ReportOutOfMemory(size, &stack); \
42 } \
43 } \
44 invoke_malloc_hook(p, size); \
45 return p;
46
47#define OPERATOR_NEW_BODY_ALIGN(mangled_name, nothrow) \
48 if (in_symbolizer()) \
49 return InternalAlloc(size, nullptr, (uptr)align); \
50 void* p = 0; \
51 { \
52 SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
53 if (UNLIKELY(!CheckAlignedNewAlignment((uptr)align))) { \
54 GET_STACK_TRACE_FATAL(thr, pc); \
55 ReportInvalidAllocationAlignment((uptr)align, &stack); \
56 } \
57 p = user_memalign(thr, pc, (uptr)align, size); \
58 if (!nothrow && UNLIKELY(!p)) { \
59 GET_STACK_TRACE_FATAL(thr, pc); \
60 ReportOutOfMemory(size, &stack); \
61 } \
62 } \
63 invoke_malloc_hook(p, size); \
64 return p;
65
66SANITIZER_INTERFACE_ATTRIBUTE
67void *operator new(__sanitizer::uptr size);
68void *operator new(__sanitizer::uptr size) {
69 OPERATOR_NEW_BODY(_Znwm, false /*nothrow*/);
70}
71
72SANITIZER_INTERFACE_ATTRIBUTE
73void *operator new[](__sanitizer::uptr size);
74void *operator new[](__sanitizer::uptr size) {
75 OPERATOR_NEW_BODY(_Znam, false /*nothrow*/);
76}
77
78SANITIZER_INTERFACE_ATTRIBUTE
79void *operator new(__sanitizer::uptr size, std::nothrow_t const&);
80void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
81 OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t, true /*nothrow*/);
82}
83
84SANITIZER_INTERFACE_ATTRIBUTE
85void *operator new[](__sanitizer::uptr size, std::nothrow_t const&);
86void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
87 OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/);
88}
89
90SANITIZER_INTERFACE_ATTRIBUTE
91void *operator new(__sanitizer::uptr size, std::align_val_t align);
92void *operator new(__sanitizer::uptr size, std::align_val_t align) {
93 OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_t, false /*nothrow*/);
94}
95
96SANITIZER_INTERFACE_ATTRIBUTE
97void *operator new[](__sanitizer::uptr size, std::align_val_t align);
98void *operator new[](__sanitizer::uptr size, std::align_val_t align) {
99 OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_t, false /*nothrow*/);
100}
101
102SANITIZER_INTERFACE_ATTRIBUTE
103void *operator new(__sanitizer::uptr size, std::align_val_t align,
104 std::nothrow_t const&);
105void *operator new(__sanitizer::uptr size, std::align_val_t align,
106 std::nothrow_t const&) {
107 OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_tRKSt9nothrow_t,
108 true /*nothrow*/);
109}
110
111SANITIZER_INTERFACE_ATTRIBUTE
112void *operator new[](__sanitizer::uptr size, std::align_val_t align,
113 std::nothrow_t const&);
114void *operator new[](__sanitizer::uptr size, std::align_val_t align,
115 std::nothrow_t const&) {
116 OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_tRKSt9nothrow_t,
117 true /*nothrow*/);
118}
119
120#define OPERATOR_DELETE_BODY(mangled_name) \
121 if (ptr == 0) return; \
122 if (in_symbolizer()) \
123 return InternalFree(ptr); \
124 invoke_free_hook(ptr); \
125 SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \
126 user_free(thr, pc, ptr);
127
128SANITIZER_INTERFACE_ATTRIBUTE
129void operator delete(void *ptr) NOEXCEPT;
130void operator delete(void *ptr) NOEXCEPT {
131 OPERATOR_DELETE_BODY(_ZdlPv);
132}
133
134SANITIZER_INTERFACE_ATTRIBUTE
135void operator delete[](void *ptr) NOEXCEPT;
136void operator delete[](void *ptr) NOEXCEPT {
137 OPERATOR_DELETE_BODY(_ZdaPv);
138}
139
140SANITIZER_INTERFACE_ATTRIBUTE
141void operator delete(void *ptr, std::nothrow_t const&);
142void operator delete(void *ptr, std::nothrow_t const&) {
143 OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t);
144}
145
146SANITIZER_INTERFACE_ATTRIBUTE
147void operator delete[](void *ptr, std::nothrow_t const&);
148void operator delete[](void *ptr, std::nothrow_t const&) {
149 OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t);
150}
151
152SANITIZER_INTERFACE_ATTRIBUTE
153void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT;
154void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT {
155 OPERATOR_DELETE_BODY(_ZdlPvm);
156}
157
158SANITIZER_INTERFACE_ATTRIBUTE
159void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT;
160void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT {
161 OPERATOR_DELETE_BODY(_ZdaPvm);
162}
163
164SANITIZER_INTERFACE_ATTRIBUTE
165void operator delete(void *ptr, std::align_val_t align) NOEXCEPT;
166void operator delete(void *ptr, std::align_val_t align) NOEXCEPT {
167 OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_t);
168}
169
170SANITIZER_INTERFACE_ATTRIBUTE
171void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT;
172void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT {
173 OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_t);
174}
175
176SANITIZER_INTERFACE_ATTRIBUTE
177void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&);
178void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) {
179 OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_tRKSt9nothrow_t);
180}
181
182SANITIZER_INTERFACE_ATTRIBUTE
183void operator delete[](void *ptr, std::align_val_t align,
184 std::nothrow_t const&);
185void operator delete[](void *ptr, std::align_val_t align,
186 std::nothrow_t const&) {
187 OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_tRKSt9nothrow_t);
188}
189
190SANITIZER_INTERFACE_ATTRIBUTE
191void operator delete(void *ptr, __sanitizer::uptr size,
192 std::align_val_t align) NOEXCEPT;
193void operator delete(void *ptr, __sanitizer::uptr size,
194 std::align_val_t align) NOEXCEPT {
195 OPERATOR_DELETE_BODY(_ZdlPvmSt11align_val_t);
196}
197
198SANITIZER_INTERFACE_ATTRIBUTE
199void operator delete[](void *ptr, __sanitizer::uptr size,
200 std::align_val_t align) NOEXCEPT;
201void operator delete[](void *ptr, __sanitizer::uptr size,
202 std::align_val_t align) NOEXCEPT {
203 OPERATOR_DELETE_BODY(_ZdaPvmSt11align_val_t);
204}
205