Skip to content

hwasan: refactor interceptor allocation/deallocation functions #145357

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
15 changes: 15 additions & 0 deletions compiler-rt/lib/hwasan/hwasan.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack);
void hwasan_free(void *ptr, StackTrace *stack);

void *hwasan_new(uptr size, StackTrace *stack);
void *hwasan_new_aligned(uptr size, uptr alignment, StackTrace *stack);
void *hwasan_new_array(uptr size, StackTrace *stack);
void *hwasan_new_array_aligned(uptr size, uptr alignment, StackTrace *stack);
void hwasan_delete(void *ptr, StackTrace *stack);
void hwasan_delete_aligned(void *ptr, uptr alignment, StackTrace *stack);
void hwasan_delete_sized(void *ptr, uptr size, StackTrace *stack);
void hwasan_delete_sized_aligned(void *ptr, uptr size, uptr alignment,
StackTrace *stack);
void hwasan_delete_array(void *ptr, StackTrace *stack);
void hwasan_delete_array_aligned(void *ptr, uptr alignment, StackTrace *stack);
void hwasan_delete_array_sized(void *ptr, uptr size, StackTrace *stack);
void hwasan_delete_array_sized_aligned(void *ptr, uptr size, uptr alignment,
StackTrace *stack);

void InstallAtExitHandler();

#define GET_MALLOC_STACK_TRACE \
Expand Down
130 changes: 115 additions & 15 deletions compiler-rt/lib/hwasan/hwasan_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ inline __lsan::ChunkTag Metadata::GetLsanTag() const {
return static_cast<__lsan::ChunkTag>(lsan_tag);
}

inline void Metadata::SetAllocType(AllocType type) { alloc_type = type; }

inline AllocType Metadata::GetAllocType() const {
return static_cast<AllocType>(alloc_type);
}

uptr GetAliasRegionStart() {
#if defined(HWASAN_ALIASING_MODE)
constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
Expand Down Expand Up @@ -181,7 +187,7 @@ static uptr TaggedSize(uptr size) {
}

static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
bool zeroise) {
AllocType alloc_type, bool zeroise) {
// Keep this consistent with LSAN and ASAN behavior.
if (UNLIKELY(orig_size == 0))
orig_size = 1;
Expand Down Expand Up @@ -259,6 +265,7 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
meta->SetLsanTag(__lsan::DisabledInThisThread() ? __lsan::kIgnored
: __lsan::kDirectlyLeaked);
#endif
meta->SetAllocType(alloc_type);
meta->SetAllocated(StackDepotPut(*stack), orig_size);
RunMallocHooks(user_ptr, orig_size);
return user_ptr;
Expand All @@ -285,7 +292,7 @@ static bool CheckInvalidFree(StackTrace *stack, void *untagged_ptr,
return false;
}

static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr, AllocType) {
CHECK(tagged_ptr);
void *untagged_ptr = UntagPtr(tagged_ptr);

Expand Down Expand Up @@ -379,15 +386,15 @@ static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old,
void *untagged_ptr_old = UntagPtr(tagged_ptr_old);
if (CheckInvalidFree(stack, untagged_ptr_old, tagged_ptr_old))
return nullptr;
void *tagged_ptr_new =
HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
void *tagged_ptr_new = HwasanAllocate(stack, new_size, alignment, FROM_MALLOC,
false /*zeroise*/);
if (tagged_ptr_old && tagged_ptr_new) {
Metadata *meta =
reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old));
void *untagged_ptr_new = UntagPtr(tagged_ptr_new);
internal_memcpy(untagged_ptr_new, untagged_ptr_old,
Min(new_size, static_cast<uptr>(meta->GetRequestedSize())));
HwasanDeallocate(stack, tagged_ptr_old);
HwasanDeallocate(stack, tagged_ptr_old, FROM_MALLOC);
}
return tagged_ptr_new;
}
Expand All @@ -398,7 +405,7 @@ static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
return nullptr;
ReportCallocOverflow(nmemb, size, stack);
}
return HwasanAllocate(stack, nmemb * size, sizeof(u64), true);
return HwasanAllocate(stack, nmemb * size, sizeof(u64), FROM_MALLOC, true);
}

HwasanChunkView FindHeapChunkByAddress(uptr address) {
Expand Down Expand Up @@ -449,7 +456,8 @@ static uptr AllocationSizeFast(const void *p) {
}

void *hwasan_malloc(uptr size, StackTrace *stack) {
return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
return SetErrnoOnNull(
HwasanAllocate(stack, size, sizeof(u64), FROM_MALLOC, false));
}

void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
Expand All @@ -458,9 +466,10 @@ void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) {

void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {
if (!ptr)
return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
return SetErrnoOnNull(
HwasanAllocate(stack, size, sizeof(u64), FROM_MALLOC, false));
if (size == 0) {
HwasanDeallocate(stack, ptr);
HwasanDeallocate(stack, ptr, FROM_MALLOC);
return nullptr;
}
return SetErrnoOnNull(HwasanReallocate(stack, ptr, size, sizeof(u64)));
Expand All @@ -478,7 +487,7 @@ void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) {

void *hwasan_valloc(uptr size, StackTrace *stack) {
return SetErrnoOnNull(
HwasanAllocate(stack, size, GetPageSizeCached(), false));
HwasanAllocate(stack, size, GetPageSizeCached(), FROM_MALLOC, false));
}

void *hwasan_pvalloc(uptr size, StackTrace *stack) {
Expand All @@ -491,7 +500,8 @@ void *hwasan_pvalloc(uptr size, StackTrace *stack) {
}
// pvalloc(0) should allocate one page.
size = size ? RoundUpTo(size, PageSize) : PageSize;
return SetErrnoOnNull(HwasanAllocate(stack, size, PageSize, false));
return SetErrnoOnNull(
HwasanAllocate(stack, size, PageSize, FROM_MALLOC, false));
}

void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
Expand All @@ -501,7 +511,8 @@ void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
return nullptr;
ReportInvalidAlignedAllocAlignment(size, alignment, stack);
}
return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
return SetErrnoOnNull(
HwasanAllocate(stack, size, alignment, FROM_MALLOC, false));
}

void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {
Expand All @@ -511,7 +522,8 @@ void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {
return nullptr;
ReportInvalidAllocationAlignment(alignment, stack);
}
return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
return SetErrnoOnNull(
HwasanAllocate(stack, size, alignment, FROM_MALLOC, false));
}

int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
Expand All @@ -521,7 +533,7 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
return errno_EINVAL;
ReportInvalidPosixMemalignAlignment(alignment, stack);
}
void *ptr = HwasanAllocate(stack, size, alignment, false);
void *ptr = HwasanAllocate(stack, size, alignment, FROM_MALLOC, false);
if (UNLIKELY(!ptr))
// OOM error is already taken care of by HwasanAllocate.
return errno_ENOMEM;
Expand All @@ -531,7 +543,95 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
}

void hwasan_free(void *ptr, StackTrace *stack) {
return HwasanDeallocate(stack, ptr);
HwasanDeallocate(stack, ptr, FROM_MALLOC);
}

namespace {

void *hwasan_new(uptr size, StackTrace *stack, bool array) {
return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64),
array ? FROM_NEW_BR : FROM_NEW, true));
}

void *hwasan_new_aligned(uptr size, uptr alignment, StackTrace *stack,
bool array) {
if (UNLIKELY(alignment == 0 || !IsPowerOfTwo(alignment))) {
errno = errno_EINVAL;
if (AllocatorMayReturnNull())
return nullptr;
ReportInvalidAllocationAlignment(alignment, stack);
}
return SetErrnoOnNull(HwasanAllocate(stack, size, alignment,
array ? FROM_NEW_BR : FROM_NEW, false));
}

void hwasan_delete(void *ptr, StackTrace *stack, bool array) {
HwasanDeallocate(stack, ptr, array ? FROM_NEW_BR : FROM_NEW);
}

void hwasan_delete_aligned(void *ptr, uptr, StackTrace *stack, bool array) {
HwasanDeallocate(stack, ptr, array ? FROM_NEW_BR : FROM_NEW);
}

void hwasan_delete_sized(void *ptr, uptr, StackTrace *stack, bool array) {
HwasanDeallocate(stack, ptr, array ? FROM_NEW_BR : FROM_NEW);
}

void hwasan_delete_sized_aligned(void *ptr, uptr, uptr, StackTrace *stack,
bool array) {
HwasanDeallocate(stack, ptr, array ? FROM_NEW_BR : FROM_NEW);
}

} // namespace

void *hwasan_new(uptr size, StackTrace *stack) {
return hwasan_new(size, stack, /*array=*/false);
}

void *hwasan_new_aligned(uptr size, uptr alignment, StackTrace *stack) {
return hwasan_new_aligned(size, alignment, stack, /*array=*/false);
}

void *hwasan_new_array(uptr size, StackTrace *stack) {
return hwasan_new(size, stack, /*array=*/true);
}

void *hwasan_new_array_aligned(uptr size, uptr alignment, StackTrace *stack) {
return hwasan_new_aligned(size, alignment, stack, /*array=*/true);
}

void hwasan_delete(void *ptr, StackTrace *stack) {
hwasan_delete(ptr, stack, /*array=*/false);
}

void hwasan_delete_aligned(void *ptr, uptr alignment, StackTrace *stack) {
hwasan_delete_aligned(ptr, alignment, stack, /*array=*/false);
}

void hwasan_delete_sized(void *ptr, uptr size, StackTrace *stack) {
hwasan_delete_sized(ptr, size, stack, /*array=*/false);
}

void hwasan_delete_sized_aligned(void *ptr, uptr size, uptr alignment,
StackTrace *stack) {
hwasan_delete_sized_aligned(ptr, size, alignment, stack, /*array=*/false);
}

void hwasan_delete_array(void *ptr, StackTrace *stack) {
hwasan_delete(ptr, stack, /*array=*/true);
}

void hwasan_delete_array_aligned(void *ptr, uptr alignment, StackTrace *stack) {
hwasan_delete_aligned(ptr, alignment, stack, /*array=*/true);
}

void hwasan_delete_array_sized(void *ptr, uptr size, StackTrace *stack) {
hwasan_delete_sized(ptr, size, stack, /*array=*/true);
}

void hwasan_delete_array_sized_aligned(void *ptr, uptr size, uptr alignment,
StackTrace *stack) {
hwasan_delete_sized_aligned(ptr, size, alignment, stack, /*array=*/true);
}

} // namespace __hwasan
Expand Down
11 changes: 10 additions & 1 deletion compiler-rt/lib/hwasan/hwasan_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,20 @@

namespace __hwasan {

enum AllocType {
FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc.
FROM_NEW = 2, // Memory block came from operator new.
FROM_NEW_BR = 3 // Memory block came from operator new [ ]
};

struct Metadata {
private:
atomic_uint64_t alloc_context_id;
u32 requested_size_low;
u16 requested_size_high;
atomic_uint8_t chunk_state;
u8 lsan_tag;
u8 lsan_tag : 2;
u8 alloc_type : 2;

public:
inline void SetAllocated(u32 stack, u64 size);
Expand All @@ -49,6 +56,8 @@ struct Metadata {
inline u32 GetAllocThreadId() const;
inline void SetLsanTag(__lsan::ChunkTag tag);
inline __lsan::ChunkTag GetLsanTag() const;
inline void SetAllocType(AllocType type);
inline AllocType GetAllocType() const;
};
static_assert(sizeof(Metadata) == 16);

Expand Down
Loading
Loading