/src/llvm-project-18.1.8.src/libcxxabi/src/stdlib_new_delete.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | inline void __throw_bad_alloc_shim() { |
32 | 0 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS |
33 | 0 | throw std::bad_alloc(); |
34 | | #else |
35 | | abort_message("bad_alloc was thrown in -fno-exceptions mode"); |
36 | | #endif |
37 | 0 | } |
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 | 13.7M | static void* operator_new_impl(std::size_t size) { |
51 | 13.7M | if (size == 0) |
52 | 0 | size = 1; |
53 | 13.7M | void* p; |
54 | 13.7M | 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 | 0 | std::new_handler nh = std::get_new_handler(); |
58 | 0 | if (nh) |
59 | 0 | nh(); |
60 | 0 | else |
61 | 0 | break; |
62 | 0 | } |
63 | 13.7M | return p; |
64 | 13.7M | } |
65 | | |
66 | 13.7M | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC { |
67 | 13.7M | void* p = operator_new_impl(size); |
68 | 13.7M | if (p == nullptr) |
69 | 0 | __throw_bad_alloc_shim(); |
70 | 13.7M | return p; |
71 | 13.7M | } |
72 | | |
73 | 0 | _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 | 0 | void* p = nullptr; |
89 | 0 | try { |
90 | 0 | p = ::operator new(size); |
91 | 0 | } catch (...) { |
92 | 0 | } |
93 | 0 | return p; |
94 | 0 | #endif |
95 | 0 | } |
96 | | |
97 | 0 | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { |
98 | 0 | return ::operator new(size); |
99 | 0 | } |
100 | | |
101 | 0 | _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 | 0 | void* p = nullptr; |
117 | 0 | try { |
118 | 0 | p = ::operator new[](size); |
119 | 0 | } catch (...) { |
120 | 0 | } |
121 | 0 | return p; |
122 | 0 | #endif |
123 | 0 | } |
124 | | |
125 | 13.7M | _LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); } |
126 | | |
127 | 0 | _LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); } |
128 | | |
129 | 0 | _LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); } |
130 | | |
131 | 0 | _LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); } |
132 | | |
133 | 0 | _LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); } |
134 | | |
135 | 0 | _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 | 73.9k | static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) { |
140 | 73.9k | if (size == 0) |
141 | 0 | size = 1; |
142 | 73.9k | if (static_cast<size_t>(alignment) < sizeof(void*)) |
143 | 0 | 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 | 73.9k | void* p; |
149 | 73.9k | while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) { |
150 | 0 | std::new_handler nh = std::get_new_handler(); |
151 | 0 | if (nh) |
152 | 0 | nh(); |
153 | 0 | else |
154 | 0 | break; |
155 | 0 | } |
156 | 73.9k | return p; |
157 | 73.9k | } |
158 | | |
159 | | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* |
160 | 73.9k | operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { |
161 | 73.9k | void* p = operator_new_aligned_impl(size, alignment); |
162 | 73.9k | if (p == nullptr) |
163 | 0 | __throw_bad_alloc_shim(); |
164 | 73.9k | return p; |
165 | 73.9k | } |
166 | | |
167 | 0 | _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 | 0 | void* p = nullptr; |
183 | 0 | try { |
184 | 0 | p = ::operator new(size, alignment); |
185 | 0 | } catch (...) { |
186 | 0 | } |
187 | 0 | return p; |
188 | 0 | # endif |
189 | 0 | } |
190 | | |
191 | | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* |
192 | 0 | operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { |
193 | 0 | return ::operator new(size, alignment); |
194 | 0 | } |
195 | | |
196 | 0 | _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 | 0 | void* p = nullptr; |
213 | 0 | try { |
214 | 0 | p = ::operator new[](size, alignment); |
215 | 0 | } catch (...) { |
216 | 0 | } |
217 | 0 | return p; |
218 | 0 | # endif |
219 | 0 | } |
220 | | |
221 | 73.9k | _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } |
222 | | |
223 | 0 | _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { |
224 | 0 | ::operator delete(ptr, alignment); |
225 | 0 | } |
226 | | |
227 | 0 | _LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept { |
228 | 0 | ::operator delete(ptr, alignment); |
229 | 0 | } |
230 | | |
231 | 0 | _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept { |
232 | 0 | ::operator delete(ptr, alignment); |
233 | 0 | } |
234 | | |
235 | 0 | _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { |
236 | 0 | ::operator delete[](ptr, alignment); |
237 | 0 | } |
238 | | |
239 | 0 | _LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept { |
240 | 0 | ::operator delete[](ptr, alignment); |
241 | 0 | } |
242 | | |
243 | | #endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION |
244 | | // ------------------ END COPY ------------------ |