xref: /llvm-project/libcxxabi/src/stdlib_new_delete.cpp (revision 4167ea2cb082a2acb00b8b1dc09aa780dc0e3110)
1eb8650a7SLouis Dionne //===----------------------------------------------------------------------===//
237812274SEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
637812274SEric Fiselier //
737812274SEric Fiselier //===----------------------------------------------------------------------===//
837812274SEric Fiselier 
937812274SEric Fiselier #include "__cxxabi_config.h"
1031452655SLouis Dionne #include "abort_message.h"
1131452655SLouis Dionne #include "include/overridable_function.h" // from libc++
1236080434SLouis Dionne #include <__memory/aligned_alloc.h>
1331452655SLouis Dionne #include <cstddef>
1437812274SEric Fiselier #include <cstdlib>
1536080434SLouis Dionne #include <new>
1637812274SEric Fiselier 
17d53cf0fdSLouis Dionne // Perform a few sanity checks on libc++ and libc++abi macros to ensure that
18d53cf0fdSLouis Dionne // the code below can be an exact copy of the code in libcxx/src/new.cpp.
19d53cf0fdSLouis Dionne #if !defined(_THROW_BAD_ALLOC)
20d53cf0fdSLouis Dionne #  error The _THROW_BAD_ALLOC macro should be already defined by libc++
2137812274SEric Fiselier #endif
22d53cf0fdSLouis Dionne 
23d53cf0fdSLouis Dionne #ifndef _LIBCPP_WEAK
24d53cf0fdSLouis Dionne #  error The _LIBCPP_WEAK macro should be already defined by libc++
25d53cf0fdSLouis Dionne #endif
26d53cf0fdSLouis Dionne 
27ba87515fSNikolas Klauser #if defined(_LIBCXXABI_NO_EXCEPTIONS) != !_LIBCPP_HAS_EXCEPTIONS
28d53cf0fdSLouis Dionne #  error libc++ and libc++abi seem to disagree on whether exceptions are enabled
29d53cf0fdSLouis Dionne #endif
30d53cf0fdSLouis Dionne 
3131452655SLouis Dionne inline void __throw_bad_alloc_shim() {
32ba87515fSNikolas Klauser #if _LIBCPP_HAS_EXCEPTIONS
3331452655SLouis Dionne   throw std::bad_alloc();
3431452655SLouis Dionne #else
35e0737174SPetr Hosek   __abort_message("bad_alloc was thrown in -fno-exceptions mode");
3631452655SLouis Dionne #endif
3731452655SLouis Dionne }
3831452655SLouis Dionne 
3931452655SLouis Dionne #define _LIBCPP_ASSERT_SHIM(expr, str)                                                                                 \
4031452655SLouis Dionne   do {                                                                                                                 \
4131452655SLouis Dionne     if (!expr)                                                                                                         \
42e0737174SPetr Hosek       __abort_message(str);                                                                                            \
4331452655SLouis Dionne   } while (false)
4431452655SLouis Dionne 
45d53cf0fdSLouis Dionne // ------------------ BEGIN COPY ------------------
46b2577e5dSEric Fiselier // Implement all new and delete operators as weak definitions
47b2577e5dSEric Fiselier // in this shared library, so that they can be overridden by programs
48b2577e5dSEric Fiselier // that define non-weak copies of the functions.
4937812274SEric Fiselier 
504207ad57Sazhan92 static void* operator_new_impl(std::size_t size) {
5137812274SEric Fiselier   if (size == 0)
5237812274SEric Fiselier     size = 1;
5337812274SEric Fiselier   void* p;
54f362be59SLouis Dionne   while ((p = std::malloc(size)) == nullptr) {
55b2577e5dSEric Fiselier     // If malloc fails and there is a new_handler,
56b2577e5dSEric Fiselier     // call it to try free up memory.
5737812274SEric Fiselier     std::new_handler nh = std::get_new_handler();
5837812274SEric Fiselier     if (nh)
5937812274SEric Fiselier       nh();
6037812274SEric Fiselier     else
6137812274SEric Fiselier       break;
6237812274SEric Fiselier   }
6337812274SEric Fiselier   return p;
6437812274SEric Fiselier }
6537812274SEric Fiselier 
66*4167ea2cSPetr Hosek _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
67e494a96aSLouis Dionne   void* p = operator_new_impl(size);
68e494a96aSLouis Dionne   if (p == nullptr)
6931452655SLouis Dionne     __throw_bad_alloc_shim();
7031452655SLouis Dionne   return p;
7131452655SLouis Dionne }
7231452655SLouis Dionne 
7331452655SLouis Dionne _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
74ba87515fSNikolas Klauser #if !_LIBCPP_HAS_EXCEPTIONS
7531452655SLouis Dionne #  if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
7631452655SLouis Dionne   _LIBCPP_ASSERT_SHIM(
77*4167ea2cSPetr Hosek       !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
7831452655SLouis Dionne       "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
7931452655SLouis Dionne       "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
8031452655SLouis Dionne       "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
8131452655SLouis Dionne       "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its "
8231452655SLouis Dionne       "contract (since it should return nullptr upon failure). Please make sure you override "
8331452655SLouis Dionne       "`operator new(size_t, nothrow_t)` as well.");
84e494a96aSLouis Dionne #  endif
85e494a96aSLouis Dionne 
8631452655SLouis Dionne   return operator_new_impl(size);
8731452655SLouis Dionne #else
88527a7fdfSBruce Mitchener   void* p = nullptr;
89f362be59SLouis Dionne   try {
9037812274SEric Fiselier     p = ::operator new(size);
91f362be59SLouis Dionne   } catch (...) {
9237812274SEric Fiselier   }
9337812274SEric Fiselier   return p;
9431452655SLouis Dionne #endif
9537812274SEric Fiselier }
9637812274SEric Fiselier 
97*4167ea2cSPetr Hosek _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
9831452655SLouis Dionne   return ::operator new(size);
9931452655SLouis Dionne }
10037812274SEric Fiselier 
10131452655SLouis Dionne _LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
102ba87515fSNikolas Klauser #if !_LIBCPP_HAS_EXCEPTIONS
10331452655SLouis Dionne #  if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
10431452655SLouis Dionne   _LIBCPP_ASSERT_SHIM(
105*4167ea2cSPetr Hosek       !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
10631452655SLouis Dionne       "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
10731452655SLouis Dionne       "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
10831452655SLouis Dionne       "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case "
10931452655SLouis Dionne       "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its "
11031452655SLouis Dionne       "contract (since it should return nullptr upon failure). Please make sure you override "
11131452655SLouis Dionne       "`operator new[](size_t, nothrow_t)` as well.");
11231452655SLouis Dionne #  endif
11331452655SLouis Dionne 
11431452655SLouis Dionne   return operator_new_impl(size);
11531452655SLouis Dionne #else
116527a7fdfSBruce Mitchener   void* p = nullptr;
117f362be59SLouis Dionne   try {
11837812274SEric Fiselier     p = ::operator new[](size);
119f362be59SLouis Dionne   } catch (...) {
12037812274SEric Fiselier   }
12137812274SEric Fiselier   return p;
12231452655SLouis Dionne #endif
12337812274SEric Fiselier }
12437812274SEric Fiselier 
12531452655SLouis Dionne _LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); }
12637812274SEric Fiselier 
12731452655SLouis Dionne _LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); }
12837812274SEric Fiselier 
12931452655SLouis Dionne _LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); }
13037812274SEric Fiselier 
13131452655SLouis Dionne _LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
13237812274SEric Fiselier 
13331452655SLouis Dionne _LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); }
134b2577e5dSEric Fiselier 
13531452655SLouis Dionne _LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); }
136b2577e5dSEric Fiselier 
137ba87515fSNikolas Klauser #if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
138b2577e5dSEric Fiselier 
1394207ad57Sazhan92 static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
140b2577e5dSEric Fiselier   if (size == 0)
141b2577e5dSEric Fiselier     size = 1;
142b2577e5dSEric Fiselier   if (static_cast<size_t>(alignment) < sizeof(void*))
143b2577e5dSEric Fiselier     alignment = std::align_val_t(sizeof(void*));
144a78aaa1aSLouis Dionne 
145a78aaa1aSLouis Dionne   // Try allocating memory. If allocation fails and there is a new_handler,
146a78aaa1aSLouis Dionne   // call it to try free up memory, and try again until it succeeds, or until
147a78aaa1aSLouis Dionne   // the new_handler decides to terminate.
148b2577e5dSEric Fiselier   void* p;
149f362be59SLouis Dionne   while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) {
150b2577e5dSEric Fiselier     std::new_handler nh = std::get_new_handler();
151b2577e5dSEric Fiselier     if (nh)
152b2577e5dSEric Fiselier       nh();
153e494a96aSLouis Dionne     else
154b2577e5dSEric Fiselier       break;
155e494a96aSLouis Dionne   }
156e494a96aSLouis Dionne   return p;
157e494a96aSLouis Dionne }
158e494a96aSLouis Dionne 
159*4167ea2cSPetr Hosek _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
160*4167ea2cSPetr Hosek operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
161e494a96aSLouis Dionne   void* p = operator_new_aligned_impl(size, alignment);
162e494a96aSLouis Dionne   if (p == nullptr)
16331452655SLouis Dionne     __throw_bad_alloc_shim();
164b2577e5dSEric Fiselier   return p;
165b2577e5dSEric Fiselier }
166b2577e5dSEric Fiselier 
16731452655SLouis Dionne _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
168ba87515fSNikolas Klauser #  if !_LIBCPP_HAS_EXCEPTIONS
16931452655SLouis Dionne #    if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
17031452655SLouis Dionne   _LIBCPP_ASSERT_SHIM(
171*4167ea2cSPetr Hosek       !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
17231452655SLouis Dionne       "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
17331452655SLouis Dionne       "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
17431452655SLouis Dionne       "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
17531452655SLouis Dionne       "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` "
17631452655SLouis Dionne       "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override "
17731452655SLouis Dionne       "`operator new(size_t, align_val_t, nothrow_t)` as well.");
17831452655SLouis Dionne #    endif
17931452655SLouis Dionne 
18031452655SLouis Dionne   return operator_new_aligned_impl(size, alignment);
18131452655SLouis Dionne #  else
182527a7fdfSBruce Mitchener   void* p = nullptr;
183f362be59SLouis Dionne   try {
184b2577e5dSEric Fiselier     p = ::operator new(size, alignment);
185f362be59SLouis Dionne   } catch (...) {
186b2577e5dSEric Fiselier   }
187b2577e5dSEric Fiselier   return p;
18831452655SLouis Dionne #  endif
189b2577e5dSEric Fiselier }
190b2577e5dSEric Fiselier 
191*4167ea2cSPetr Hosek _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
192*4167ea2cSPetr Hosek operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
193*4167ea2cSPetr Hosek   return ::operator new(size, alignment);
194*4167ea2cSPetr Hosek }
195b2577e5dSEric Fiselier 
19631452655SLouis Dionne _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
197ba87515fSNikolas Klauser #  if !_LIBCPP_HAS_EXCEPTIONS
19831452655SLouis Dionne #    if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
19931452655SLouis Dionne   _LIBCPP_ASSERT_SHIM(
200*4167ea2cSPetr Hosek       !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
20131452655SLouis Dionne       "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
20231452655SLouis Dionne       "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
20331452655SLouis Dionne       "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
20431452655SLouis Dionne       "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
20531452655SLouis Dionne       "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
20631452655SLouis Dionne       "override "
20731452655SLouis Dionne       "`operator new[](size_t, align_val_t, nothrow_t)` as well.");
20831452655SLouis Dionne #    endif
20931452655SLouis Dionne 
21031452655SLouis Dionne   return operator_new_aligned_impl(size, alignment);
21131452655SLouis Dionne #  else
212527a7fdfSBruce Mitchener   void* p = nullptr;
213f362be59SLouis Dionne   try {
214b2577e5dSEric Fiselier     p = ::operator new[](size, alignment);
215f362be59SLouis Dionne   } catch (...) {
216b2577e5dSEric Fiselier   }
217b2577e5dSEric Fiselier   return p;
21831452655SLouis Dionne #  endif
219b2577e5dSEric Fiselier }
220b2577e5dSEric Fiselier 
22131452655SLouis Dionne _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); }
222b2577e5dSEric Fiselier 
22331452655SLouis Dionne _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
224b2577e5dSEric Fiselier   ::operator delete(ptr, alignment);
225b2577e5dSEric Fiselier }
226b2577e5dSEric Fiselier 
22731452655SLouis Dionne _LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept {
22831452655SLouis Dionne   ::operator delete(ptr, alignment);
22931452655SLouis Dionne }
230b2577e5dSEric Fiselier 
23131452655SLouis Dionne _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept {
23231452655SLouis Dionne   ::operator delete(ptr, alignment);
23331452655SLouis Dionne }
234b2577e5dSEric Fiselier 
23531452655SLouis Dionne _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
236b2577e5dSEric Fiselier   ::operator delete[](ptr, alignment);
237b2577e5dSEric Fiselier }
238b2577e5dSEric Fiselier 
23931452655SLouis Dionne _LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept {
24031452655SLouis Dionne   ::operator delete[](ptr, alignment);
24131452655SLouis Dionne }
242b2577e5dSEric Fiselier 
243ba87515fSNikolas Klauser #endif // _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
244d53cf0fdSLouis Dionne // ------------------ END COPY ------------------
245