[compiler-rt] 415b1cf - Add __sanitizer_get_allocated_begin API and implementations
Thurston Dang via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 3 14:45:31 PDT 2023
Author: Thurston Dang
Date: 2023-04-03T21:27:51Z
New Revision: 415b1cfd57de62da8af9ad8dc567fc9d918dbaa5
URL: https://github.com/llvm/llvm-project/commit/415b1cfd57de62da8af9ad8dc567fc9d918dbaa5
DIFF: https://github.com/llvm/llvm-project/commit/415b1cfd57de62da8af9ad8dc567fc9d918dbaa5.diff
LOG: Add __sanitizer_get_allocated_begin API and implementations
This function will return the start of the allocation, if given a pointer that lies within an allocation. Otherwise, it returns NULL.
It will be useful for detecting dynamic TLS allocations in glibc >=2.25, which
uses malloc (see https://github.com/google/sanitizers/issues/1409#issuecomment-1214244142).
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D147005
Added:
compiler-rt/test/sanitizer_common/TestCases/get_allocated_begin.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_allocator_internal.h
compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
compiler-rt/lib/tsan/rtl/tsan_mman.cpp
Removed:
################################################################################
diff --git a/compiler-rt/include/sanitizer/allocator_interface.h b/compiler-rt/include/sanitizer/allocator_interface.h
index 6226135ef84b3..d846f3f330741 100644
--- a/compiler-rt/include/sanitizer/allocator_interface.h
+++ b/compiler-rt/include/sanitizer/allocator_interface.h
@@ -26,6 +26,10 @@ extern "C" {
is not yet freed. */
int __sanitizer_get_ownership(const volatile void *p);
+ /* If a pointer lies within an allocation, it will return the start address
+ of the allocation. Otherwise, it returns nullptr. */
+ void *__sanitizer_get_allocated_begin(const void *p);
+
/* Returns the number of bytes reserved for the pointer p.
Requires (get_ownership(p) == true) or (p == 0). */
size_t __sanitizer_get_allocated_size(const volatile void *p);
diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp
index 4c52a45b875c7..4b65b44a88f91 100644
--- a/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/compiler-rt/lib/asan/asan_allocator.cpp
@@ -1164,6 +1164,17 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
// ---------------------- Interface ---------------- {{{1
using namespace __asan;
+void *AllocationBegin(const void *p) {
+ AsanChunk *m = __asan::instance.GetAsanChunkByAddr((uptr)p);
+ if (!m)
+ return nullptr;
+ if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
+ return nullptr;
+ if (m->UsedSize() == 0)
+ return nullptr;
+ return (void *)(m->Beg());
+}
+
// ASan allocator doesn't reserve extra bytes, so normally we would
// just return "size". We don't want to expose our redzone sizes, etc here.
uptr __sanitizer_get_estimated_allocated_size(uptr size) {
@@ -1187,6 +1198,10 @@ uptr __sanitizer_get_allocated_size(const void *p) {
return allocated_size;
}
+void *__sanitizer_get_allocated_begin(const void *p) {
+ return AllocationBegin(p);
+}
+
void __sanitizer_purge_allocator() {
GET_STACK_TRACE_MALLOC;
instance.Purge(&stack);
diff --git a/compiler-rt/lib/dfsan/dfsan_allocator.cpp b/compiler-rt/lib/dfsan/dfsan_allocator.cpp
index 5fb8fef213b9a..cebf9983c9490 100644
--- a/compiler-rt/lib/dfsan/dfsan_allocator.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_allocator.cpp
@@ -174,6 +174,20 @@ void *DFsanCalloc(uptr nmemb, uptr size) {
return DFsanAllocate(nmemb * size, sizeof(u64), true /*zeroise*/);
}
+void *AllocationBegin(const void *p) {
+ if (!p)
+ return nullptr;
+ const void *beg = allocator.GetBlockBegin(p);
+ if (!beg)
+ return nullptr;
+ Metadata *b = (Metadata *)allocator.GetMetaData(beg);
+ if (!b)
+ return nullptr;
+ if (b->requested_size == 0)
+ return nullptr;
+ return (void *)beg;
+}
+
static uptr AllocationSize(const void *p) {
if (!p)
return 0;
@@ -294,4 +308,8 @@ uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
+void *__sanitizer_get_allocated_begin(const void *p) {
+ return AllocationBegin(p);
+}
+
uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
index d096a8faa2c7e..8ccdeb23fa995 100644
--- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
@@ -397,6 +397,23 @@ HwasanChunkView FindHeapChunkByAddress(uptr address) {
return HwasanChunkView(reinterpret_cast<uptr>(block), metadata);
}
+void *AllocationBegin(const void *p) {
+ const void *untagged_ptr = UntagPtr(p);
+ if (!untagged_ptr)
+ return nullptr;
+
+ const void *beg = allocator.GetBlockBegin(untagged_ptr);
+ if (!beg)
+ return nullptr;
+
+ Metadata *b = (Metadata *)allocator.GetMetaData(beg);
+ if (b->GetRequestedSize() == 0)
+ return nullptr;
+
+ tag_t tag = GetTagFromPointer((uptr)p);
+ return (void *)AddTagToPointer((uptr)beg, tag);
+}
+
static uptr AllocationSize(const void *tagged_ptr) {
const void *untagged_ptr = UntagPtr(tagged_ptr);
if (!untagged_ptr) return 0;
@@ -641,4 +658,8 @@ uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
+void *__sanitizer_get_allocated_begin(const void *p) {
+ return AllocationBegin(p);
+}
+
uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp
index 37ba363d479dd..d50882657dc33 100644
--- a/compiler-rt/lib/lsan/lsan_allocator.cpp
+++ b/compiler-rt/lib/lsan/lsan_allocator.cpp
@@ -145,6 +145,22 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end) {
*end = *begin + sizeof(AllocatorCache);
}
+void *GetMallocBegin(const void *p) {
+ if (!p)
+ return nullptr;
+ const void *beg = allocator.GetBlockBegin(p);
+ if (!beg)
+ return nullptr;
+ ChunkMetadata *m = Metadata(beg);
+ if (!m)
+ return nullptr;
+ if (!m->allocated)
+ return nullptr;
+ if (m->requested_size == 0)
+ return nullptr;
+ return (void *)beg;
+}
+
uptr GetMallocUsableSize(const void *p) {
if (!p)
return 0;
@@ -363,6 +379,11 @@ uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_get_ownership(const void *p) { return Metadata(p) != nullptr; }
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_get_allocated_begin(const void *p) {
+ return GetMallocBegin(p);
+}
+
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_allocated_size(const void *p) {
return GetMallocUsableSize(p);
diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp
index 51c3a66ebd680..80a87d49dfc6e 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.cpp
+++ b/compiler-rt/lib/memprof/memprof_allocator.cpp
@@ -681,6 +681,18 @@ int memprof_posix_memalign(void **memptr, uptr alignment, uptr size,
return 0;
}
+void *memprof_malloc_begin(const void *p) {
+ u64 user_requested_size;
+ MemprofChunk *m =
+ instance.GetMemprofChunkByAddr((uptr)p, user_requested_size);
+ if (!m)
+ return nullptr;
+ if (user_requested_size == 0)
+ return nullptr;
+
+ return (void *)m->Beg();
+}
+
uptr memprof_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
if (!ptr)
return 0;
@@ -699,6 +711,10 @@ int __sanitizer_get_ownership(const void *p) {
return memprof_malloc_usable_size(p, 0, 0) != 0;
}
+void *__sanitizer_get_allocated_begin(const void *p) {
+ return memprof_malloc_begin(p);
+}
+
uptr __sanitizer_get_allocated_size(const void *p) {
return memprof_malloc_usable_size(p, 0, 0);
}
diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp
index 3308ee7053a61..a760a434158a5 100644
--- a/compiler-rt/lib/msan/msan_allocator.cpp
+++ b/compiler-rt/lib/msan/msan_allocator.cpp
@@ -260,6 +260,21 @@ static void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
return MsanAllocate(stack, nmemb * size, sizeof(u64), true);
}
+void *AllocationBegin(const void *p) {
+ if (!p)
+ return nullptr;
+ const void *beg = allocator.GetBlockBegin(p);
+ if (!beg)
+ return nullptr;
+ Metadata *b = (Metadata *)allocator.GetMetaData(beg);
+ if (!b)
+ return nullptr;
+ if (b->requested_size == 0)
+ return nullptr;
+
+ return (void *)beg;
+}
+
static uptr AllocationSize(const void *p) {
if (!p) return 0;
const void *beg = allocator.GetBlockBegin(p);
@@ -373,4 +388,8 @@ uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
+void *__sanitizer_get_allocated_begin(const void *p) {
+ return AllocationBegin(p);
+}
+
uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
index c1b27563e2fc7..35c7c97df3299 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
@@ -21,6 +21,8 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_estimated_allocated_size(uptr size);
SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 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_current_allocated_bytes();
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
index 38994736877ac..adbdad5a1ee0c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -51,7 +51,8 @@ void InternalFree(void *p, InternalAllocatorCache *cache = nullptr);
void InternalAllocatorLock();
void InternalAllocatorUnlock();
InternalAllocator *internal_allocator();
-
+int __sanitizer_get_allocation_bounds(const void *p, void **start,
+ unsigned long long *size);
} // namespace __sanitizer
#endif // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
index 958f071e7b5f7..01be600e33ba3 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
@@ -32,6 +32,7 @@ INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc)
INTERFACE_FUNCTION(__sanitizer_symbolize_global)
INTERFACE_FUNCTION(__sanitizer_symbolize_pc)
// Allocator interface.
+INTERFACE_FUNCTION(__sanitizer_get_allocated_begin)
INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
index 99fa492265615..9c548dfff91f3 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
@@ -352,6 +352,20 @@ void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) {
return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize));
}
+void *user_alloc_begin(const void *p) {
+ if (p == nullptr || !IsAppMem((uptr)p))
+ return nullptr;
+ const void *beg = allocator()->GetBlockBegin(p);
+ if (!beg)
+ return nullptr;
+
+ MBlock *b = ctx->metamap.GetBlock((uptr)beg);
+ if (!b)
+ return nullptr; // Not a valid pointer.
+
+ return (void *)beg;
+}
+
uptr user_alloc_usable_size(const void *p) {
if (p == 0 || !IsAppMem((uptr)p))
return 0;
@@ -430,6 +444,10 @@ int __sanitizer_get_ownership(const void *p) {
return allocator()->GetBlockBegin(p) != 0;
}
+void *__sanitizer_get_allocated_begin(const void *p) {
+ return user_alloc_begin(p);
+}
+
uptr __sanitizer_get_allocated_size(const void *p) {
return user_alloc_usable_size(p);
}
diff --git a/compiler-rt/test/sanitizer_common/TestCases/get_allocated_begin.cpp b/compiler-rt/test/sanitizer_common/TestCases/get_allocated_begin.cpp
new file mode 100644
index 0000000000000..6892a4a7fb282
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/get_allocated_begin.cpp
@@ -0,0 +1,58 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t
+
+// UBSan does not have its own allocator
+// UNSUPPORTED: ubsan
+
+#include <assert.h>
+#include <sanitizer/allocator_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Based on lib/msan/tests/msan_test.cpp::get_allocated_size_and_ownership
+int main(void) {
+ int sizes[] = {10, 100, 1000, 10000, 100000, 1000000};
+
+ for (int i = 0; i < sizeof(sizes) / sizeof(int); i++) {
+ printf("Testing size %d\n", sizes[i]);
+
+ char *array = reinterpret_cast<char *>(malloc(sizes[i]));
+ int *int_ptr = new int;
+ printf("array: %p\n", array);
+ printf("int_ptr: %p\n", int_ptr);
+
+ // Bogus value to unpoison start. Calling __sanitizer_get_allocated_begin
+ // does not unpoison it.
+ void *start = NULL;
+ for (int j = 0; j < sizes[i]; j++) {
+ printf("j: %d\n", j);
+
+ start = __sanitizer_get_allocated_begin(array + j);
+ printf("Start: %p (expected: %p)\n", start, array);
+ fflush(stdout);
+ assert(array == start);
+ }
+
+ start = __sanitizer_get_allocated_begin(int_ptr);
+ assert(int_ptr == start);
+
+ void *wild_addr = reinterpret_cast<void *>(4096 * 160);
+ assert(__sanitizer_get_allocated_begin(wild_addr) == NULL);
+
+ wild_addr = reinterpret_cast<void *>(0x1);
+ assert(__sanitizer_get_allocated_begin(wild_addr) == NULL);
+
+ // NULL is a valid argument for GetAllocatedSize but is not owned.
+ assert(__sanitizer_get_allocated_begin(NULL) == NULL);
+
+ free(array);
+ for (int j = 0; j < sizes[i]; j++) {
+ assert(__sanitizer_get_allocated_begin(array + j) == NULL);
+ }
+
+ delete int_ptr;
+ assert(__sanitizer_get_allocated_begin(int_ptr) == NULL);
+ }
+
+ return 0;
+}
More information about the llvm-commits
mailing list