Skip to content

hwasan: refactor new/delete interceptor macros #146698

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 2 commits into from
Jul 8, 2025
Merged
Changes from all 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
112 changes: 85 additions & 27 deletions compiler-rt/lib/hwasan/hwasan_new_delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,90 @@
#if HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE

// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
# define OPERATOR_NEW_BODY(nothrow) \
# define OPERATOR_NEW_BODY \
GET_MALLOC_STACK_TRACE; \
void *res = hwasan_malloc(size, &stack); \
if (!nothrow && UNLIKELY(!res)) \
if (UNLIKELY(!res)) \
ReportOutOfMemory(size, &stack); \
return res
# define OPERATOR_NEW_ALIGN_BODY(nothrow) \
# define OPERATOR_NEW_BODY_NOTHROW \
GET_MALLOC_STACK_TRACE; \
return hwasan_malloc(size, &stack)
# define OPERATOR_NEW_BODY_ARRAY \
GET_MALLOC_STACK_TRACE; \
void *res = hwasan_malloc(size, &stack); \
if (UNLIKELY(!res)) \
ReportOutOfMemory(size, &stack); \
return res
# define OPERATOR_NEW_BODY_ARRAY_NOTHROW \
GET_MALLOC_STACK_TRACE; \
return hwasan_malloc(size, &stack)
# define OPERATOR_NEW_BODY_ALIGN \
GET_MALLOC_STACK_TRACE; \
void *res = hwasan_memalign(static_cast<uptr>(align), size, &stack); \
if (UNLIKELY(!res)) \
ReportOutOfMemory(size, &stack); \
return res
# define OPERATOR_NEW_BODY_ALIGN_NOTHROW \
GET_MALLOC_STACK_TRACE; \
return hwasan_memalign(static_cast<uptr>(align), size, &stack)
# define OPERATOR_NEW_BODY_ALIGN_ARRAY \
GET_MALLOC_STACK_TRACE; \
void *res = hwasan_memalign(static_cast<uptr>(align), size, &stack); \
if (!nothrow && UNLIKELY(!res)) \
if (UNLIKELY(!res)) \
ReportOutOfMemory(size, &stack); \
return res
# define OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW \
GET_MALLOC_STACK_TRACE; \
return hwasan_memalign(static_cast<uptr>(align), size, &stack)

# define OPERATOR_DELETE_BODY \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)
# define OPERATOR_DELETE_BODY_ARRAY \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)
# define OPERATOR_DELETE_BODY_ALIGN \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)
# define OPERATOR_DELETE_BODY_ALIGN_ARRAY \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)
# define OPERATOR_DELETE_BODY_SIZE \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)
# define OPERATOR_DELETE_BODY_SIZE_ARRAY \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)
# define OPERATOR_DELETE_BODY_SIZE_ALIGN \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)
# define OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY \
GET_MALLOC_STACK_TRACE; \
if (ptr) \
hwasan_free(ptr, &stack)

#elif defined(__ANDROID__)

// We don't actually want to intercept operator new and delete on Android, but
// since we previously released a runtime that intercepted these functions,
// removing the interceptors would break ABI. Therefore we simply forward to
// malloc and free.
# define OPERATOR_NEW_BODY(nothrow) return malloc(size)
# define OPERATOR_NEW_BODY return malloc(size)
# define OPERATOR_NEW_BODY_NOTHROW return malloc(size)
# define OPERATOR_NEW_BODY_ARRAY return malloc(size)
# define OPERATOR_NEW_BODY_ARRAY_NOTHROW return malloc(size)
# define OPERATOR_DELETE_BODY free(ptr)
# define OPERATOR_DELETE_BODY_ARRAY free(ptr)
# define OPERATOR_DELETE_BODY_SIZE free(ptr)
# define OPERATOR_DELETE_BODY_SIZE_ARRAY free(ptr)

#endif

Expand All @@ -61,19 +119,19 @@ struct nothrow_t {};
} // namespace std

INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(size_t size) {
OPERATOR_NEW_BODY(false /*nothrow*/);
OPERATOR_NEW_BODY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
size_t size) {
OPERATOR_NEW_BODY(false /*nothrow*/);
OPERATOR_NEW_BODY_ARRAY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
size_t size, std::nothrow_t const &) {
OPERATOR_NEW_BODY(true /*nothrow*/);
OPERATOR_NEW_BODY_NOTHROW;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
size_t size, std::nothrow_t const &) {
OPERATOR_NEW_BODY(true /*nothrow*/);
OPERATOR_NEW_BODY_ARRAY_NOTHROW;
}

INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
Expand All @@ -82,81 +140,81 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
void *ptr) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_ARRAY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
void *ptr, std::nothrow_t const &) {
OPERATOR_DELETE_BODY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
void *ptr, std::nothrow_t const &) {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_ARRAY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
void *ptr, size_t) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_SIZE;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
void *ptr, size_t) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_SIZE_ARRAY;
}

#endif // OPERATOR_NEW_BODY

#ifdef OPERATOR_NEW_ALIGN_BODY
#ifdef OPERATOR_NEW_BODY_ALIGN

namespace std {
enum class align_val_t : size_t {};
} // namespace std

INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
size_t size, std::align_val_t align) {
OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
OPERATOR_NEW_BODY_ALIGN;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
size_t size, std::align_val_t align) {
OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
OPERATOR_NEW_BODY_ALIGN_ARRAY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
size_t size, std::align_val_t align, std::nothrow_t const &) {
OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
OPERATOR_NEW_BODY_ALIGN_NOTHROW;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
size_t size, std::align_val_t align, std::nothrow_t const &) {
OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW;
}

INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
void *ptr, std::align_val_t align) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_ALIGN;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
void *ptr, std::align_val_t) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_ALIGN_ARRAY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_ALIGN;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_ALIGN_ARRAY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
void *ptr, size_t, std::align_val_t) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_SIZE_ALIGN;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
void *ptr, size_t, std::align_val_t) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
void *ptr, size_t, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_SIZE_ALIGN;
}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
void *ptr, size_t, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
OPERATOR_DELETE_BODY;
OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY;
}

#endif // OPERATOR_NEW_ALIGN_BODY
#endif // OPERATOR_NEW_BODY_ALIGN
Loading