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 <cstddef>
10#include <cstdlib>
11#include <new>
12
13#include "include/aligned_alloc.h"
14#include "include/overridable_function.h"
15
16// libc++ and libc++abi have different assertion mechanisms, so we need different implementations of
17// `__throw_bad_alloc_shim` and `_LIBCPP_ASSERT_SHIM` for them in -fno-exceptions mode. These are expected to be
18// provided before including this file.
19void __throw_bad_alloc_shim();
20
21#ifndef _LIBCPP_ASSERT_SHIM
22# error _LIBCPP_ASSERT_SHIM should be defined
23# define _LIBCPP_ASSERT_SHIM // make the file parseable
24#endif
25
26enum class on_failure {
27 return_null,
28 throw_bad_alloc,
29};
30
31template <on_failure failure_mode>
32static void* operator_new_impl(std::size_t size) {
33 if (size == 0)
34 size = 1;
35 void* p;
36 while ((p = std::malloc(size: size)) == nullptr) {
37 // If malloc fails and there is a new_handler,
38 // call it to try free up memory.
39 std::new_handler nh = std::get_new_handler();
40 if (nh)
41 nh();
42 else
43 break;
44 }
45 if (failure_mode == on_failure::throw_bad_alloc && !p)
46 __throw_bad_alloc_shim();
47 return p;
48}
49
50OVERRIDABLE_FUNCTION void* operator new(std::size_t size) _THROW_BAD_ALLOC {
51 return operator_new_impl<on_failure::throw_bad_alloc>(size);
52}
53
54[[gnu::weak]] void* operator new(size_t size, const std::nothrow_t&) noexcept {
55#if !_LIBCPP_HAS_EXCEPTIONS
56# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
57 _LIBCPP_ASSERT_SHIM(
58 (!std::__is_function_overridden < void*(std::size_t), &operator new>()),
59 "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
60 "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
61 "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
62 "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its "
63 "contract (since it should return nullptr upon failure). Please make sure you override "
64 "`operator new(size_t, nothrow_t)` as well.");
65# endif
66
67 return operator_new_impl<on_failure::return_null>(size);
68#else
69 void* p = nullptr;
70 try {
71 p = ::operator new(size);
72 } catch (...) {
73 }
74 return p;
75#endif
76}
77
78OVERRIDABLE_FUNCTION void* operator new[](size_t size) _THROW_BAD_ALLOC { return ::operator new(size); }
79
80[[gnu::weak]] void* operator new[](size_t size, const std::nothrow_t&) noexcept {
81#if !_LIBCPP_HAS_EXCEPTIONS
82# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
83 _LIBCPP_ASSERT_SHIM(
84 (!std::__is_function_overridden < 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<on_failure::return_null>(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[[gnu::weak]] void operator delete(void* ptr) noexcept { std::free(ptr: ptr); }
105
106[[gnu::weak]] void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); }
107
108[[gnu::weak]] void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); }
109
110[[gnu::weak]] void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
111
112[[gnu::weak]] void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); }
113
114[[gnu::weak]] void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); }
115
116#if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
117
118template <on_failure failure_mode>
119static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
120 if (size == 0)
121 size = 1;
122 if (static_cast<size_t>(alignment) < sizeof(void*))
123 alignment = std::align_val_t(sizeof(void*));
124
125 // Try allocating memory. If allocation fails and there is a new_handler,
126 // call it to try free up memory, and try again until it succeeds, or until
127 // the new_handler decides to terminate.
128 void* p;
129 while ((p = std::__libcpp_aligned_alloc(alignment: static_cast<std::size_t>(alignment), size: size)) == nullptr) {
130 std::new_handler nh = std::get_new_handler();
131 if (nh)
132 nh();
133 else
134 break;
135 }
136 if (failure_mode == on_failure::throw_bad_alloc && !p)
137 __throw_bad_alloc_shim();
138 return p;
139}
140
141OVERRIDABLE_FUNCTION void* operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
142 return operator_new_aligned_impl<on_failure::throw_bad_alloc>(size, alignment);
143}
144
145[[gnu::weak]] void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
146# if !_LIBCPP_HAS_EXCEPTIONS
147# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
148 _LIBCPP_ASSERT_SHIM(
149 (!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new>()),
150 "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
151 "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
152 "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
153 "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` "
154 "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override "
155 "`operator new(size_t, align_val_t, nothrow_t)` as well.");
156# endif
157
158 return operator_new_aligned_impl<on_failure::return_null>(size, alignment);
159# else
160 void* p = nullptr;
161 try {
162 p = ::operator new(size, alignment);
163 } catch (...) {
164 }
165 return p;
166# endif
167}
168
169OVERRIDABLE_FUNCTION void* operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
170 return ::operator new(size, alignment);
171}
172
173[[gnu::weak]] void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
174# if !_LIBCPP_HAS_EXCEPTIONS
175# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
176 _LIBCPP_ASSERT_SHIM(
177 (!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new[]>()),
178 "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
179 "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
180 "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
181 "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
182 "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
183 "override `operator new[](size_t, align_val_t, nothrow_t)` as well.");
184# endif
185
186 return operator_new_aligned_impl<on_failure::return_null>(size, alignment);
187# else
188 void* p = nullptr;
189 try {
190 p = ::operator new[](size, alignment);
191 } catch (...) {
192 }
193 return p;
194# endif
195}
196
197[[gnu::weak]] void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr: ptr); }
198
199[[gnu::weak]] void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
200 ::operator delete(ptr, alignment);
201}
202
203[[gnu::weak]] void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept {
204 ::operator delete(ptr, alignment);
205}
206
207[[gnu::weak]] void operator delete[](void* ptr, std::align_val_t alignment) noexcept {
208 ::operator delete(ptr, alignment);
209}
210
211[[gnu::weak]] void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
212 ::operator delete[](ptr, alignment);
213}
214
215[[gnu::weak]] void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept {
216 ::operator delete[](ptr, alignment);
217}
218#endif // _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
219