diff --git a/compiler-rt/include/sanitizer/allocator_interface.h b/compiler-rt/include/sanitizer/allocator_interface.h --- a/compiler-rt/include/sanitizer/allocator_interface.h +++ b/compiler-rt/include/sanitizer/allocator_interface.h @@ -34,6 +34,10 @@ Requires (get_ownership(p) == true) or (p == 0). */ size_t __sanitizer_get_allocated_size(const volatile void *p); + /* Returns the number of bytes reserved for the pointer p. + Requires __sanitizer_get_allocated_begin(p) == p. */ + size_t __sanitizer_get_allocated_size_fast(const volatile void *p); + /* Number of bytes, allocated and not yet freed by the application. */ size_t __sanitizer_get_current_allocated_bytes(void); diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp --- a/compiler-rt/lib/asan/asan_allocator.cpp +++ b/compiler-rt/lib/asan/asan_allocator.cpp @@ -798,6 +798,10 @@ return m->UsedSize(); } + uptr AllocationSizeFast(uptr p) { + return reinterpret_cast(p - kChunkHeaderSize)->UsedSize(); + } + AsanChunkView FindHeapChunkByAddress(uptr addr) { AsanChunk *m1 = GetAsanChunkByAddr(addr); sptr offset = 0; @@ -1198,6 +1202,13 @@ return allocated_size; } +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = instance.AllocationSizeFast(reinterpret_cast(p)); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} + const void *__sanitizer_get_allocated_begin(const void *p) { return AllocationBegin(p); } diff --git a/compiler-rt/lib/dfsan/dfsan_allocator.cpp b/compiler-rt/lib/dfsan/dfsan_allocator.cpp --- a/compiler-rt/lib/dfsan/dfsan_allocator.cpp +++ b/compiler-rt/lib/dfsan/dfsan_allocator.cpp @@ -198,6 +198,10 @@ return b->requested_size; } +static uptr AllocationSizeFast(const void *p) { + return reinterpret_cast(allocator.GetMetaData(p))->requested_size; +} + void *dfsan_malloc(uptr size) { return SetErrnoOnNull(DFsanAllocate(size, sizeof(u64), false /*zeroise*/)); } @@ -313,3 +317,10 @@ } uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); } + +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = AllocationSizeFast(p); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -442,6 +442,15 @@ return b->GetRequestedSize(); } +static uptr AllocationSizeFast(const void *p) { + const void *untagged_ptr = UntagPtr(p); + void *aligned_ptr = reinterpret_cast( + RoundDownTo(reinterpret_cast(untagged_ptr), kShadowAlignment)); + Metadata *meta = + reinterpret_cast(allocator.GetMetaData(aligned_ptr)); + return meta->GetRequestedSize(); +} + void *hwasan_malloc(uptr size, StackTrace *stack) { return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false)); } @@ -680,4 +689,11 @@ uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); } +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = AllocationSizeFast(p); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} + void __sanitizer_purge_allocator() { allocator.ForceReleaseToOS(); } diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -172,6 +172,10 @@ return m->requested_size; } +uptr GetMallocUsableSizeFast(const void *p) { + return Metadata(p)->requested_size; +} + int lsan_posix_memalign(void **memptr, uptr alignment, uptr size, const StackTrace &stack) { if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { @@ -385,6 +389,14 @@ return GetMallocUsableSize(p); } +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = GetMallocUsableSizeFast(p); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_purge_allocator() { allocator.ForceReleaseToOS(); } diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp --- a/compiler-rt/lib/memprof/memprof_allocator.cpp +++ b/compiler-rt/lib/memprof/memprof_allocator.cpp @@ -555,6 +555,10 @@ return user_requested_size; } + uptr AllocationSizeFast(uptr p) { + return reinterpret_cast(p - kChunkHeaderSize)->UsedSize(); + } + void Purge(BufferedStackTrace *stack) { allocator.ForceReleaseToOS(); } void PrintStats() { allocator.PrintStats(); } @@ -719,6 +723,13 @@ return memprof_malloc_usable_size(p, 0, 0); } +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = instance.AllocationSizeFast(reinterpret_cast(p)); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} + int __memprof_profile_dump() { instance.FinishAndWrite(); // In the future we may want to return non-zero if there are any errors diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp --- a/compiler-rt/lib/msan/msan_allocator.cpp +++ b/compiler-rt/lib/msan/msan_allocator.cpp @@ -288,6 +288,10 @@ return b->requested_size; } +static uptr AllocationSizeFast(const void *p) { + return reinterpret_cast(allocator.GetMetaData(p))->requested_size; +} + void *msan_malloc(uptr size, StackTrace *stack) { return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); } @@ -399,4 +403,11 @@ uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); } +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = AllocationSizeFast(p); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} + void __sanitizer_purge_allocator() { allocator.ForceReleaseToOS(); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h @@ -25,6 +25,8 @@ const void *p); SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_allocated_size(const void *p); +SANITIZER_INTERFACE_ATTRIBUTE uptr +__sanitizer_get_allocated_size_fast(const void *p); SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes(); SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size(); SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes(); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc @@ -34,6 +34,7 @@ // Allocator interface. INTERFACE_FUNCTION(__sanitizer_get_allocated_begin) INTERFACE_FUNCTION(__sanitizer_get_allocated_size) +INTERFACE_FUNCTION(__sanitizer_get_allocated_size_fast) INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_free_bytes) diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp @@ -377,6 +377,13 @@ return b->siz; } +uptr user_alloc_usable_size_fast(const void *p) { + MBlock *b = ctx->metamap.GetBlock((uptr)p); + if (b->siz == 0) + return 1; // Zero-sized allocations are actually 1 byte. + return b->siz; +} + void invoke_malloc_hook(void *ptr, uptr size) { ThreadState *thr = cur_thread(); if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors) @@ -452,6 +459,13 @@ return user_alloc_usable_size(p); } +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = user_alloc_usable_size_fast(p); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} + void __sanitizer_purge_allocator() { allocator()->ForceReleaseToOS(); } diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/malloc_usable_size.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/malloc_usable_size.c --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/malloc_usable_size.c +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/malloc_usable_size.c @@ -17,12 +17,14 @@ int size = 1; p = malloc(size); assert(__sanitizer_get_allocated_size(p) == size); + assert(__sanitizer_get_allocated_size_fast(p) == size); assert(malloc_usable_size(p) == size); free(p); size = 1234567; p = malloc(size); assert(__sanitizer_get_allocated_size(p) == size); + assert(__sanitizer_get_allocated_size_fast(p) == size); assert(malloc_usable_size(p) == size); free(p); return 0; diff --git a/compiler-rt/test/sanitizer_common/TestCases/allocator_interface.cpp b/compiler-rt/test/sanitizer_common/TestCases/allocator_interface.cpp --- a/compiler-rt/test/sanitizer_common/TestCases/allocator_interface.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/allocator_interface.cpp @@ -17,6 +17,7 @@ assert(__sanitizer_get_ownership(p)); assert(!__sanitizer_get_ownership(&p)); assert(__sanitizer_get_allocated_size(p) == size); + assert(__sanitizer_get_allocated_size_fast(p) == size); assert(__sanitizer_get_allocated_begin(p) == p); assert(__sanitizer_get_allocated_begin(p + 1) == p); assert(__sanitizer_get_current_allocated_bytes() >= diff --git a/compiler-rt/test/sanitizer_common/TestCases/malloc_hook_get_allocated_size_fast.cpp b/compiler-rt/test/sanitizer_common/TestCases/malloc_hook_get_allocated_size_fast.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/malloc_hook_get_allocated_size_fast.cpp @@ -0,0 +1,56 @@ +// RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 + +// Malloc/free hooks are not supported on Windows. +// XFAIL: target={{.*windows-msvc.*}} + +// Must not be implemented, no other reason to install interceptors. +// XFAIL: ubsan + +// FIXME: Implement. +// XFAIL: hwasan + +#include +#include +#include +#include + +extern "C" { +const volatile void *global_ptr; + +// Note: avoid calling functions that allocate memory in malloc/free +// to avoid infinite recursion. +void __sanitizer_malloc_hook(const volatile void *ptr, size_t sz) { + if (__sanitizer_get_ownership(ptr) && sz == sizeof(int)) { + global_ptr = ptr; + assert(__sanitizer_get_allocated_size_fast(ptr) == sizeof(int)); + } +} +void __sanitizer_free_hook(const volatile void *ptr) { + if (__sanitizer_get_ownership(ptr) && ptr == global_ptr) + assert(__sanitizer_get_allocated_size_fast(ptr) == sizeof(int)); +} +} // extern "C" + +volatile int *x; + +// Call this function with uninitialized arguments to poison +// TLS shadow for function parameters before calling operator +// new and, eventually, user-provided hook. +__attribute__((noinline)) void allocate(int *unused1, int *unused2) { + x = reinterpret_cast(malloc(sizeof(int))); +} + +int main() { + int *undef1, *undef2; + allocate(undef1, undef2); + + // Check that malloc hook was called with correct argument. + if (global_ptr != (void *)x) { + _exit(1); + } + + *x = -8; + free((void *)x); + + return 0; +}