Coverage Report

Created: 2025-06-14 06:33

/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 ------------------