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