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) != defined(_LIBCPP_HAS_NO_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 | #ifndef _LIBCPP_HAS_NO_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)) == 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_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK 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 | #ifdef _LIBCPP_HAS_NO_EXCEPTIONS |
75 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION |
76 | _LIBCPP_ASSERT_SHIM( |
77 | !std::__is_function_overridden(static_cast<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_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { |
98 | return ::operator new(size); |
99 | } |
100 | |
101 | _LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { |
102 | #ifdef _LIBCPP_HAS_NO_EXCEPTIONS |
103 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION |
104 | _LIBCPP_ASSERT_SHIM( |
105 | !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])), |
106 | "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, " |
107 | "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because " |
108 | "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case " |
109 | "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its " |
110 | "contract (since it should return nullptr upon failure). Please make sure you override " |
111 | "`operator new[](size_t, nothrow_t)` as well." ); |
112 | # endif |
113 | |
114 | return operator_new_impl(size); |
115 | #else |
116 | void* p = nullptr; |
117 | try { |
118 | p = ::operator new[](size); |
119 | } catch (...) { |
120 | } |
121 | return p; |
122 | #endif |
123 | } |
124 | |
125 | _LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); } |
126 | |
127 | _LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); } |
128 | |
129 | _LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); } |
130 | |
131 | _LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); } |
132 | |
133 | _LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); } |
134 | |
135 | _LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); } |
136 | |
137 | #if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) |
138 | |
139 | static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) { |
140 | if (size == 0) |
141 | size = 1; |
142 | if (static_cast<size_t>(alignment) < sizeof(void*)) |
143 | alignment = std::align_val_t(sizeof(void*)); |
144 | |
145 | // Try allocating memory. If allocation fails and there is a new_handler, |
146 | // call it to try free up memory, and try again until it succeeds, or until |
147 | // the new_handler decides to terminate. |
148 | void* p; |
149 | while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) { |
150 | std::new_handler nh = std::get_new_handler(); |
151 | if (nh) |
152 | nh(); |
153 | else |
154 | break; |
155 | } |
156 | return p; |
157 | } |
158 | |
159 | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* |
160 | operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { |
161 | void* p = operator_new_aligned_impl(size, alignment); |
162 | if (p == nullptr) |
163 | __throw_bad_alloc_shim(); |
164 | return p; |
165 | } |
166 | |
167 | _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { |
168 | # ifdef _LIBCPP_HAS_NO_EXCEPTIONS |
169 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION |
170 | _LIBCPP_ASSERT_SHIM( |
171 | !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)), |
172 | "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, " |
173 | "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " |
174 | "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will " |
175 | "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` " |
176 | "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override " |
177 | "`operator new(size_t, align_val_t, nothrow_t)` as well." ); |
178 | # endif |
179 | |
180 | return operator_new_aligned_impl(size, alignment); |
181 | # else |
182 | void* p = nullptr; |
183 | try { |
184 | p = ::operator new(size, alignment); |
185 | } catch (...) { |
186 | } |
187 | return p; |
188 | # endif |
189 | } |
190 | |
191 | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* |
192 | operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { |
193 | return ::operator new(size, alignment); |
194 | } |
195 | |
196 | _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { |
197 | # ifdef _LIBCPP_HAS_NO_EXCEPTIONS |
198 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION |
199 | _LIBCPP_ASSERT_SHIM( |
200 | !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])), |
201 | "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, " |
202 | "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " |
203 | "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will " |
204 | "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, " |
205 | "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you " |
206 | "override " |
207 | "`operator new[](size_t, align_val_t, nothrow_t)` as well." ); |
208 | # endif |
209 | |
210 | return operator_new_aligned_impl(size, alignment); |
211 | # else |
212 | void* p = nullptr; |
213 | try { |
214 | p = ::operator new[](size, alignment); |
215 | } catch (...) { |
216 | } |
217 | return p; |
218 | # endif |
219 | } |
220 | |
221 | _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } |
222 | |
223 | _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { |
224 | ::operator delete(ptr, alignment); |
225 | } |
226 | |
227 | _LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept { |
228 | ::operator delete(ptr, alignment); |
229 | } |
230 | |
231 | _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept { |
232 | ::operator delete(ptr, alignment); |
233 | } |
234 | |
235 | _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { |
236 | ::operator delete[](ptr, alignment); |
237 | } |
238 | |
239 | _LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept { |
240 | ::operator delete[](ptr, alignment); |
241 | } |
242 | |
243 | #endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION |
244 | // ------------------ END COPY ------------------ |
245 | |