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