xref: /llvm-project/libcxxabi/src/stdlib_new_delete.cpp (revision 4167ea2cb082a2acb00b8b1dc09aa780dc0e3110)
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)) == 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 #if !_LIBCPP_HAS_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 #if !_LIBCPP_HAS_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 _LIBCPP_HAS_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 #  if !_LIBCPP_HAS_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 #  if !_LIBCPP_HAS_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_LIBRARY_ALIGNED_ALLOCATION
244 // ------------------ END COPY ------------------
245