[compiler-rt] 7639265 - [sanitizer] Implement __sanitizer_get_allocated_size_fast
Jin Xin Ng via llvm-commits
llvm-commits at lists.llvm.org
Thu May 25 17:21:43 PDT 2023
Author: Jin Xin Ng
Date: 2023-05-26T00:19:47Z
New Revision: 7639265af4547c0330d5949f0da8f92e9b83f6b0
URL: https://github.com/llvm/llvm-project/commit/7639265af4547c0330d5949f0da8f92e9b83f6b0
DIFF: https://github.com/llvm/llvm-project/commit/7639265af4547c0330d5949f0da8f92e9b83f6b0.diff
LOG: [sanitizer] Implement __sanitizer_get_allocated_size_fast
The primary motivation for this change is to allow FreeHooks to obtain
the allocated size of the pointer being freed in a fast, efficient manner.
Differential Revision: https://reviews.llvm.org/D151360
Added:
compiler-rt/test/sanitizer_common/TestCases/malloc_hook_get_allocated_size_fast.cpp
Modified:
compiler-rt/include/sanitizer/allocator_interface.h
compiler-rt/lib/asan/asan_allocator.cpp
compiler-rt/lib/dfsan/dfsan_allocator.cpp
compiler-rt/lib/hwasan/hwasan_allocator.cpp
compiler-rt/lib/lsan/lsan_allocator.cpp
compiler-rt/lib/memprof/memprof_allocator.cpp
compiler-rt/lib/msan/msan_allocator.cpp
compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
compiler-rt/lib/tsan/rtl/tsan_mman.cpp
compiler-rt/test/sanitizer_common/TestCases/Linux/malloc_usable_size.c
compiler-rt/test/sanitizer_common/TestCases/allocator_interface.cpp
Removed:
################################################################################
diff --git a/compiler-rt/include/sanitizer/allocator_interface.h b/compiler-rt/include/sanitizer/allocator_interface.h
index d0cfce79c1aef..367e6409258f1 100644
--- a/compiler-rt/include/sanitizer/allocator_interface.h
+++ b/compiler-rt/include/sanitizer/allocator_interface.h
@@ -34,6 +34,10 @@ extern "C" {
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
index 19d7777c40282..5f26118d0e67a 100644
--- a/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/compiler-rt/lib/asan/asan_allocator.cpp
@@ -798,6 +798,10 @@ struct Allocator {
return m->UsedSize();
}
+ uptr AllocationSizeFast(uptr p) {
+ return reinterpret_cast<AsanChunk *>(p - kChunkHeaderSize)->UsedSize();
+ }
+
AsanChunkView FindHeapChunkByAddress(uptr addr) {
AsanChunk *m1 = GetAsanChunkByAddr(addr);
sptr offset = 0;
@@ -1198,6 +1202,13 @@ uptr __sanitizer_get_allocated_size(const void *p) {
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<uptr>(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
index 3075b6da1c115..a3bed535dc08b 100644
--- a/compiler-rt/lib/dfsan/dfsan_allocator.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_allocator.cpp
@@ -198,6 +198,10 @@ static uptr AllocationSize(const void *p) {
return b->requested_size;
}
+static uptr AllocationSizeFast(const void *p) {
+ return reinterpret_cast<Metadata *>(allocator.GetMetaData(p))->requested_size;
+}
+
void *dfsan_malloc(uptr size) {
return SetErrnoOnNull(DFsanAllocate(size, sizeof(u64), false /*zeroise*/));
}
@@ -313,3 +317,10 @@ const void *__sanitizer_get_allocated_begin(const void *p) {
}
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
index d3e8266726302..6e6e63517b762 100644
--- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
@@ -442,6 +442,15 @@ static uptr AllocationSize(const void *p) {
return b->GetRequestedSize();
}
+static uptr AllocationSizeFast(const void *p) {
+ const void *untagged_ptr = UntagPtr(p);
+ void *aligned_ptr = reinterpret_cast<void *>(
+ RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
+ Metadata *meta =
+ reinterpret_cast<Metadata *>(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 @@ const void *__sanitizer_get_allocated_begin(const void *p) {
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
index b7c088508f2f6..12d579a9385b1 100644
--- a/compiler-rt/lib/lsan/lsan_allocator.cpp
+++ b/compiler-rt/lib/lsan/lsan_allocator.cpp
@@ -172,6 +172,10 @@ uptr GetMallocUsableSize(const void *p) {
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 @@ uptr __sanitizer_get_allocated_size(const void *p) {
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
index 1e0d05d47a6f8..4b68f21272844 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.cpp
+++ b/compiler-rt/lib/memprof/memprof_allocator.cpp
@@ -555,6 +555,10 @@ struct Allocator {
return user_requested_size;
}
+ uptr AllocationSizeFast(uptr p) {
+ return reinterpret_cast<MemprofChunk *>(p - kChunkHeaderSize)->UsedSize();
+ }
+
void Purge(BufferedStackTrace *stack) { allocator.ForceReleaseToOS(); }
void PrintStats() { allocator.PrintStats(); }
@@ -719,6 +723,13 @@ uptr __sanitizer_get_allocated_size(const void *p) {
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<uptr>(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
index 96fdf7bb195f2..be0714dbf47e2 100644
--- a/compiler-rt/lib/msan/msan_allocator.cpp
+++ b/compiler-rt/lib/msan/msan_allocator.cpp
@@ -288,6 +288,10 @@ static uptr AllocationSize(const void *p) {
return b->requested_size;
}
+static uptr AllocationSizeFast(const void *p) {
+ return reinterpret_cast<Metadata *>(allocator.GetMetaData(p))->requested_size;
+}
+
void *msan_malloc(uptr size, StackTrace *stack) {
return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false));
}
@@ -399,4 +403,11 @@ const void *__sanitizer_get_allocated_begin(const void *p) {
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
index 8f3b71eb6ce74..de2b271fb0ed9 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
@@ -25,6 +25,8 @@ SANITIZER_INTERFACE_ATTRIBUTE const void *__sanitizer_get_allocated_begin(
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
index 01be600e33ba3..37efb5791d0bf 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
@@ -34,6 +34,7 @@ INTERFACE_FUNCTION(__sanitizer_symbolize_pc)
// 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
index 94f850eee0275..ac6d005fc1c05 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
@@ -377,6 +377,13 @@ uptr user_alloc_usable_size(const void *p) {
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 @@ uptr __sanitizer_get_allocated_size(const void *p) {
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
index 07abb1fa29363..0fdec468e08ae 100644
--- 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 main() {
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
index c2f304418f86a..6f5f05639800a 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/allocator_interface.cpp
+++ b/compiler-rt/test/sanitizer_common/TestCases/allocator_interface.cpp
@@ -17,6 +17,7 @@ void Test(int size) {
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
index 0000000000000..7acd2f698d642
--- /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 <assert.h>
+#include <sanitizer/allocator_interface.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+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<int *>(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;
+}
More information about the llvm-commits
mailing list