Skip to content

Commit 25a03c1

Browse files
authored
[libcxx][NFC] Use macros for functions that support overriding detection (llvm#133876)
We plan to replace the existing mechanism for overriding detection with one that doesn't require the use of a special section as an alternative to llvm#120805 which had other downsides. This change is a pure refactoring that lays the foundation for a subsequent change that will introduce the new detection mechanism.
1 parent 7babf22 commit 25a03c1

File tree

3 files changed

+29
-38
lines changed

3 files changed

+29
-38
lines changed

libcxx/src/include/overridable_function.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@
6666
#if defined(_LIBCPP_OBJECT_FORMAT_MACHO)
6767

6868
# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1
69-
# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE \
70-
__attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions")))
69+
# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) \
70+
__attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions"))) _LIBCPP_WEAK type name arglist
7171

7272
_LIBCPP_BEGIN_NAMESPACE_STD
73-
template <class _Ret, class... _Args>
74-
_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept {
73+
template <typename T, T* _Func>
74+
_LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
7575
// Declare two dummy bytes and give them these special `__asm` values. These values are
7676
// defined by the linker, which means that referring to `&__lcxx_override_start` will
7777
// effectively refer to the address where the section starts (and same for the end).
@@ -81,7 +81,7 @@ _LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) no
8181
// Now get a uintptr_t out of these locations, and out of the function pointer.
8282
uintptr_t __start = reinterpret_cast<uintptr_t>(&__lcxx_override_start);
8383
uintptr_t __end = reinterpret_cast<uintptr_t>(&__lcxx_override_end);
84-
uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr);
84+
uintptr_t __ptr = reinterpret_cast<uintptr_t>(_Func);
8585

8686
# if __has_feature(ptrauth_calls)
8787
// We must pass a void* to ptrauth_strip since it only accepts a pointer type. Also, in particular,
@@ -100,7 +100,8 @@ _LIBCPP_END_NAMESPACE_STD
100100
#elif defined(_LIBCPP_OBJECT_FORMAT_ELF) && !defined(__NVPTX__)
101101

102102
# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1
103-
# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE __attribute__((__section__("__lcxx_override")))
103+
# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) \
104+
__attribute__((__section__("__lcxx_override"))) _LIBCPP_WEAK type name arglist
104105

105106
// This is very similar to what we do for Mach-O above. The ELF linker will implicitly define
106107
// variables with those names corresponding to the start and the end of the section.
@@ -110,11 +111,11 @@ extern char __start___lcxx_override;
110111
extern char __stop___lcxx_override;
111112

112113
_LIBCPP_BEGIN_NAMESPACE_STD
113-
template <class _Ret, class... _Args>
114-
_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept {
114+
template <typename T, T* _Func>
115+
_LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
115116
uintptr_t __start = reinterpret_cast<uintptr_t>(&__start___lcxx_override);
116117
uintptr_t __end = reinterpret_cast<uintptr_t>(&__stop___lcxx_override);
117-
uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr);
118+
uintptr_t __ptr = reinterpret_cast<uintptr_t>(_Func);
118119

119120
# if __has_feature(ptrauth_calls)
120121
// We must pass a void* to ptrauth_strip since it only accepts a pointer type. See full explanation above.
@@ -128,7 +129,7 @@ _LIBCPP_END_NAMESPACE_STD
128129
#else
129130

130131
# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 0
131-
# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE /* nothing */
132+
# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) _LIBCPP_WEAK type name arglist
132133

133134
#endif
134135

libcxx/src/new.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ static void* operator_new_impl(std::size_t size) {
4343
return p;
4444
}
4545

46-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
46+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size)) _THROW_BAD_ALLOC {
4747
void* p = operator_new_impl(size);
4848
if (p == nullptr)
4949
__throw_bad_alloc_shim();
@@ -54,7 +54,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
5454
# if !_LIBCPP_HAS_EXCEPTIONS
5555
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
5656
_LIBCPP_ASSERT_SHIM(
57-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
57+
(!std::__is_function_overridden < void*(std::size_t), &operator new>()),
5858
"libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
5959
"but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
6060
"`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
@@ -74,15 +74,13 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
7474
# endif
7575
}
7676

77-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
78-
return ::operator new(size);
79-
}
77+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size)) _THROW_BAD_ALLOC { return ::operator new(size); }
8078

8179
_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
8280
# if !_LIBCPP_HAS_EXCEPTIONS
8381
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
8482
_LIBCPP_ASSERT_SHIM(
85-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
83+
(!std::__is_function_overridden < void*(std::size_t), &operator new[]>()),
8684
"libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
8785
"but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
8886
"`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case "
@@ -136,8 +134,7 @@ static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignm
136134
return p;
137135
}
138136

139-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
140-
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
137+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
141138
void* p = operator_new_aligned_impl(size, alignment);
142139
if (p == nullptr)
143140
__throw_bad_alloc_shim();
@@ -148,7 +145,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
148145
# if !_LIBCPP_HAS_EXCEPTIONS
149146
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
150147
_LIBCPP_ASSERT_SHIM(
151-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
148+
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new>()),
152149
"libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
153150
"but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
154151
"`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
@@ -168,23 +165,21 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
168165
# endif
169166
}
170167

171-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
172-
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
168+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
173169
return ::operator new(size, alignment);
174170
}
175171

176172
_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
177173
# if !_LIBCPP_HAS_EXCEPTIONS
178174
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
179175
_LIBCPP_ASSERT_SHIM(
180-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
176+
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new[]>()),
181177
"libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
182178
"but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
183179
"`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
184180
"terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
185181
"nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
186-
"override "
187-
"`operator new[](size_t, align_val_t, nothrow_t)` as well.");
182+
"override `operator new[](size_t, align_val_t, nothrow_t)` as well.");
188183
# endif
189184

190185
return operator_new_aligned_impl(size, alignment);

libcxxabi/src/stdlib_new_delete.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static void* operator_new_impl(std::size_t size) {
6363
return p;
6464
}
6565

66-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
66+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size)) _THROW_BAD_ALLOC {
6767
void* p = operator_new_impl(size);
6868
if (p == nullptr)
6969
__throw_bad_alloc_shim();
@@ -74,7 +74,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
7474
#if !_LIBCPP_HAS_EXCEPTIONS
7575
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
7676
_LIBCPP_ASSERT_SHIM(
77-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
77+
(!std::__is_function_overridden < void*(std::size_t), &operator new>()),
7878
"libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
7979
"but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
8080
"`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
@@ -94,15 +94,13 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
9494
#endif
9595
}
9696

97-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
98-
return ::operator new(size);
99-
}
97+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size)) _THROW_BAD_ALLOC { return ::operator new(size); }
10098

10199
_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
102100
#if !_LIBCPP_HAS_EXCEPTIONS
103101
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
104102
_LIBCPP_ASSERT_SHIM(
105-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
103+
(!std::__is_function_overridden < void*(std::size_t), &operator new[]>()),
106104
"libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
107105
"but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
108106
"`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case "
@@ -156,8 +154,7 @@ static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignm
156154
return p;
157155
}
158156

159-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
160-
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
157+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
161158
void* p = operator_new_aligned_impl(size, alignment);
162159
if (p == nullptr)
163160
__throw_bad_alloc_shim();
@@ -168,7 +165,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
168165
# if !_LIBCPP_HAS_EXCEPTIONS
169166
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
170167
_LIBCPP_ASSERT_SHIM(
171-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
168+
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new>()),
172169
"libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
173170
"but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
174171
"`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
@@ -188,23 +185,21 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
188185
# endif
189186
}
190187

191-
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
192-
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
188+
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
193189
return ::operator new(size, alignment);
194190
}
195191

196192
_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
197193
# if !_LIBCPP_HAS_EXCEPTIONS
198194
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
199195
_LIBCPP_ASSERT_SHIM(
200-
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
196+
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new[]>()),
201197
"libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
202198
"but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
203199
"`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
204200
"terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
205201
"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.");
202+
"override `operator new[](size_t, align_val_t, nothrow_t)` as well.");
208203
# endif
209204

210205
return operator_new_aligned_impl(size, alignment);

0 commit comments

Comments
 (0)