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 | |
31 | inline 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 | |
50 | static 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 | |
137 | static 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 | |