Skip to content

[libcxx][NFC] Use macros for functions that support overriding detection #133876

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions libcxx/src/include/overridable_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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,
Expand All @@ -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.
Expand All @@ -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.
Expand Down
23 changes: 9 additions & 14 deletions libcxx/src/new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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 "
Expand All @@ -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 "
Expand Down Expand Up @@ -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();
Expand All @@ -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 "
Expand All @@ -168,23 +165,21 @@ _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);
}

_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, 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, 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);
Expand Down
23 changes: 9 additions & 14 deletions libcxxabi/src/stdlib_new_delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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 "
Expand All @@ -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 "
Expand Down Expand Up @@ -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();
Expand All @@ -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 "
Expand All @@ -188,23 +185,21 @@ _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);
}

_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, 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, 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);
Expand Down
Loading