1//===----------------------------------------------------------------------===//
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#include "__cxxabi_config.h"
10#include "abort_message.h"
11#include "include/aligned_alloc.h" // from libc++
12#include "include/overridable_function.h" // from libc++
13#include <cstddef>
14#include <cstdlib>
15#include <new>
16
17// Perform a few sanity checks on libc++ and libc++abi macros to ensure that
18// the code below can be an exact copy of the code in libcxx/src/new.cpp.
19#if !defined(_THROW_BAD_ALLOC)
20# error The _THROW_BAD_ALLOC macro should be already defined by libc++
21#endif
22
23#if defined(_LIBCXXABI_NO_EXCEPTIONS) != !_LIBCPP_HAS_EXCEPTIONS
24# error libc++ and libc++abi seem to disagree on whether exceptions are enabled
25#endif
26
27inline void __throw_bad_alloc_shim() {
28#if _LIBCPP_HAS_EXCEPTIONS
29 throw std::bad_alloc();
30#else
31 __abort_message("bad_alloc was thrown in -fno-exceptions mode");
32#endif
33}
34
35#define _LIBCPP_ASSERT_SHIM(expr, str) \
36 do { \
37 if (!expr) \
38 __abort_message(str); \
39 } while (false)
40
41// ------------------ BEGIN COPY ------------------
42// Implement all new and delete operators as weak definitions
43// in this shared library, so that they can be overridden by programs
44// that define non-weak copies of the functions.
45
46static void* operator_new_impl(std::size_t size) {
47 if (size == 0)
48 size = 1;
49 void* p;
50 while ((p = std::malloc(size: size)) == nullptr) {
51 // If malloc fails and there is a new_handler,
52 // call it to try free up memory.
53 std::new_handler nh = std::get_new_handler();
54 if (nh)
55 nh();
56 else
57 break;
58 }
59 return p;
60}
61
62OVERRIDABLE_FUNCTION void* operator new(std::size_t size) _THROW_BAD_ALLOC {
63 void* p = operator_new_impl(size);
64 if (p == nullptr)
65 __throw_bad_alloc_shim();
66 return p;
67}
68
69[[gnu::weak]] void* operator new(size_t size, const std::nothrow_t&) noexcept {
70#if !_LIBCPP_HAS_EXCEPTIONS
71# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
72 _LIBCPP_ASSERT_SHIM(
73 (!std::__is_function_overridden < void*(std::size_t), &operator new>()),
74 "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
75 "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
76 "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
77 "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its "
78 "contract (since it should return nullptr upon failure). Please make sure you override "
79 "`operator new(size_t, nothrow_t)` as well.");
80# endif
81
82 return operator_new_impl(size);
83#else
84 void* p = nullptr;
85 try {
86 p = ::operator new(size);
87 } catch (...) {
88 }
89 return p;
90#endif
91}
92
93OVERRIDABLE_FUNCTION void* operator new[](size_t size) _THROW_BAD_ALLOC { return ::operator new(size); }
94
95[[gnu::weak]] void* operator new[](size_t size, const std::nothrow_t&) noexcept {
96#if !_LIBCPP_HAS_EXCEPTIONS
97# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
98 _LIBCPP_ASSERT_SHIM(
99 (!std::__is_function_overridden < void*(std::size_t), &operator new[]>()),
100 "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
101 "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
102 "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case "
103 "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its "
104 "contract (since it should return nullptr upon failure). Please make sure you override "
105 "`operator new[](size_t, nothrow_t)` as well.");
106# endif
107
108 return operator_new_impl(size);
109#else
110 void* p = nullptr;
111 try {
112 p = ::operator new[](size);
113 } catch (...) {
114 }
115 return p;
116#endif
117}
118
119[[gnu::weak]] void operator delete(void* ptr) noexcept { std::free(ptr: ptr); }
120
121[[gnu::weak]] void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); }
122
123[[gnu::weak]] void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); }
124
125[[gnu::weak]] void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
126
127[[gnu::weak]] void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); }
128
129[[gnu::weak]] void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); }
130
131#if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
132
133static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
134 if (size == 0)
135 size = 1;
136 if (static_cast<size_t>(alignment) < sizeof(void*))
137 alignment = std::align_val_t(sizeof(void*));
138
139 // Try allocating memory. If allocation fails and there is a new_handler,
140 // call it to try free up memory, and try again until it succeeds, or until
141 // the new_handler decides to terminate.
142 void* p;
143 while ((p = std::__libcpp_aligned_alloc(alignment: static_cast<std::size_t>(alignment), size: size)) == nullptr) {
144 std::new_handler nh = std::get_new_handler();
145 if (nh)
146 nh();
147 else
148 break;
149 }
150 return p;
151}
152
153OVERRIDABLE_FUNCTION void* operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
154 void* p = operator_new_aligned_impl(size, alignment);
155 if (p == nullptr)
156 __throw_bad_alloc_shim();
157 return p;
158}
159
160[[gnu::weak]] void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
161# if !_LIBCPP_HAS_EXCEPTIONS
162# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
163 _LIBCPP_ASSERT_SHIM(
164 (!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new>()),
165 "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
166 "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
167 "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
168 "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` "
169 "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override "
170 "`operator new(size_t, align_val_t, nothrow_t)` as well.");
171# endif
172
173 return operator_new_aligned_impl(size, alignment);
174# else
175 void* p = nullptr;
176 try {
177 p = ::operator new(size, alignment);
178 } catch (...) {
179 }
180 return p;
181# endif
182}
183
184OVERRIDABLE_FUNCTION void* operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
185 return ::operator new(size, alignment);
186}
187
188[[gnu::weak]] void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
189# if !_LIBCPP_HAS_EXCEPTIONS
190# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
191 _LIBCPP_ASSERT_SHIM(
192 (!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new[]>()),
193 "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
194 "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
195 "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
196 "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
197 "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
198 "override `operator new[](size_t, align_val_t, nothrow_t)` as well.");
199# endif
200
201 return operator_new_aligned_impl(size, alignment);
202# else
203 void* p = nullptr;
204 try {
205 p = ::operator new[](size, alignment);
206 } catch (...) {
207 }
208 return p;
209# endif
210}
211
212[[gnu::weak]] void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr: ptr); }
213
214[[gnu::weak]] void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
215 ::operator delete(ptr, alignment);
216}
217
218[[gnu::weak]] void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept {
219 ::operator delete(ptr, alignment);
220}
221
222[[gnu::weak]] void operator delete[](void* ptr, std::align_val_t alignment) noexcept {
223 ::operator delete(ptr, alignment);
224}
225
226[[gnu::weak]] void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
227 ::operator delete[](ptr, alignment);
228}
229
230[[gnu::weak]] void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept {
231 ::operator delete[](ptr, alignment);
232}
233
234#endif // _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
235// ------------------ END COPY ------------------
236