[libcxx][NFC] Use macros for functions that support overriding detection (#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/llvm-project#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.
This commit is contained in:
parent
7babf22461
commit
25a03c1c7c
@ -66,12 +66,12 @@
|
||||
#if defined(_LIBCPP_OBJECT_FORMAT_MACHO)
|
||||
|
||||
# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1
|
||||
# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE \
|
||||
__attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions")))
|
||||
# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) \
|
||||
__attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions"))) _LIBCPP_WEAK type name arglist
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
template <class _Ret, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept {
|
||||
template <typename T, T* _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
|
||||
// Declare two dummy bytes and give them these special `__asm` values. These values are
|
||||
// defined by the linker, which means that referring to `&__lcxx_override_start` will
|
||||
// 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
|
||||
// Now get a uintptr_t out of these locations, and out of the function pointer.
|
||||
uintptr_t __start = reinterpret_cast<uintptr_t>(&__lcxx_override_start);
|
||||
uintptr_t __end = reinterpret_cast<uintptr_t>(&__lcxx_override_end);
|
||||
uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr);
|
||||
uintptr_t __ptr = reinterpret_cast<uintptr_t>(_Func);
|
||||
|
||||
# if __has_feature(ptrauth_calls)
|
||||
// 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
|
||||
#elif defined(_LIBCPP_OBJECT_FORMAT_ELF) && !defined(__NVPTX__)
|
||||
|
||||
# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1
|
||||
# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE __attribute__((__section__("__lcxx_override")))
|
||||
# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) \
|
||||
__attribute__((__section__("__lcxx_override"))) _LIBCPP_WEAK type name arglist
|
||||
|
||||
// This is very similar to what we do for Mach-O above. The ELF linker will implicitly define
|
||||
// variables with those names corresponding to the start and the end of the section.
|
||||
@ -110,11 +111,11 @@ extern char __start___lcxx_override;
|
||||
extern char __stop___lcxx_override;
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
template <class _Ret, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept {
|
||||
template <typename T, T* _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
|
||||
uintptr_t __start = reinterpret_cast<uintptr_t>(&__start___lcxx_override);
|
||||
uintptr_t __end = reinterpret_cast<uintptr_t>(&__stop___lcxx_override);
|
||||
uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr);
|
||||
uintptr_t __ptr = reinterpret_cast<uintptr_t>(_Func);
|
||||
|
||||
# if __has_feature(ptrauth_calls)
|
||||
// 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
|
||||
#else
|
||||
|
||||
# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 0
|
||||
# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE /* nothing */
|
||||
# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) _LIBCPP_WEAK type name arglist
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -43,7 +43,7 @@ static void* operator_new_impl(std::size_t size) {
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size)) _THROW_BAD_ALLOC {
|
||||
void* p = operator_new_impl(size);
|
||||
if (p == nullptr)
|
||||
__throw_bad_alloc_shim();
|
||||
@ -54,7 +54,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
|
||||
# if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
|
||||
(!std::__is_function_overridden < void*(std::size_t), &operator new>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
|
||||
"but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`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 {
|
||||
# endif
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
|
||||
return ::operator new(size);
|
||||
}
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size)) _THROW_BAD_ALLOC { return ::operator new(size); }
|
||||
|
||||
_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
|
||||
# if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
|
||||
(!std::__is_function_overridden < void*(std::size_t), &operator new[]>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
|
||||
"but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`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
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
|
||||
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
|
||||
void* p = operator_new_aligned_impl(size, alignment);
|
||||
if (p == nullptr)
|
||||
__throw_bad_alloc_shim();
|
||||
@ -148,7 +145,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
|
||||
# if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
|
||||
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
|
||||
"but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
|
||||
@ -168,8 +165,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
|
||||
# endif
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
|
||||
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
|
||||
return ::operator new(size, alignment);
|
||||
}
|
||||
|
||||
@ -177,14 +173,13 @@ _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const
|
||||
# if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
|
||||
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new[]>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
|
||||
"but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
|
||||
"terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
|
||||
"nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
|
||||
"override "
|
||||
"`operator new[](size_t, align_val_t, nothrow_t)` as well.");
|
||||
"override `operator new[](size_t, align_val_t, nothrow_t)` as well.");
|
||||
# endif
|
||||
|
||||
return operator_new_aligned_impl(size, alignment);
|
||||
|
@ -63,7 +63,7 @@ static void* operator_new_impl(std::size_t size) {
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size)) _THROW_BAD_ALLOC {
|
||||
void* p = operator_new_impl(size);
|
||||
if (p == nullptr)
|
||||
__throw_bad_alloc_shim();
|
||||
@ -74,7 +74,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
|
||||
#if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
|
||||
(!std::__is_function_overridden < void*(std::size_t), &operator new>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
|
||||
"but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`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 {
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
|
||||
return ::operator new(size);
|
||||
}
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size)) _THROW_BAD_ALLOC { return ::operator new(size); }
|
||||
|
||||
_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
|
||||
#if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
|
||||
(!std::__is_function_overridden < void*(std::size_t), &operator new[]>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
|
||||
"but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`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
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
|
||||
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
|
||||
void* p = operator_new_aligned_impl(size, alignment);
|
||||
if (p == nullptr)
|
||||
__throw_bad_alloc_shim();
|
||||
@ -168,7 +165,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
|
||||
# if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
|
||||
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
|
||||
"but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
|
||||
@ -188,8 +185,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s
|
||||
# endif
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
|
||||
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
|
||||
_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC {
|
||||
return ::operator new(size, alignment);
|
||||
}
|
||||
|
||||
@ -197,14 +193,13 @@ _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const
|
||||
# if !_LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
|
||||
(!std::__is_function_overridden < void*(std::size_t, std::align_val_t), &operator new[]>()),
|
||||
"libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
|
||||
"but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
|
||||
"terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
|
||||
"nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
|
||||
"override "
|
||||
"`operator new[](size_t, align_val_t, nothrow_t)` as well.");
|
||||
"override `operator new[](size_t, align_val_t, nothrow_t)` as well.");
|
||||
# endif
|
||||
|
||||
return operator_new_aligned_impl(size, alignment);
|
||||
|
Loading…
x
Reference in New Issue
Block a user