[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