[compiler-rt] r334505 - [scudo] Add C++17 aligned new/delete operators support

Kostya Kortchinsky via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 12 07:42:41 PDT 2018


Author: cryptoad
Date: Tue Jun 12 07:42:40 2018
New Revision: 334505

URL: http://llvm.org/viewvc/llvm-project?rev=334505&view=rev
Log:
[scudo] Add C++17 aligned new/delete operators support

Summary:
This CL adds support for aligned new/delete operators (C++17). Currently we
do not support alignment inconsistency detection on deallocation, as this
requires a header change, but the APIs are introduced and are functional.

Add a smoke test for the aligned version of the operators.

Reviewers: alekseyshl

Reviewed By: alekseyshl

Subscribers: delcypher, #sanitizers, llvm-commits

Differential Revision: https://reviews.llvm.org/D48031

Added:
    compiler-rt/trunk/test/scudo/aligned-new.cpp
Modified:
    compiler-rt/trunk/lib/scudo/scudo_allocator.cpp
    compiler-rt/trunk/lib/scudo/scudo_allocator.h
    compiler-rt/trunk/lib/scudo/scudo_malloc.cpp
    compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp

Modified: compiler-rt/trunk/lib/scudo/scudo_allocator.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_allocator.cpp?rev=334505&r1=334504&r2=334505&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_allocator.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_allocator.cpp Tue Jun 12 07:42:40 2018
@@ -480,7 +480,8 @@ struct ScudoAllocator {
 
   // Deallocates a Chunk, which means either adding it to the quarantine or
   // directly returning it to the backend if criteria are met.
-  void deallocate(void *Ptr, uptr DeleteSize, AllocType Type) {
+  void deallocate(void *Ptr, uptr DeleteSize, uptr DeleteAlignment,
+                  AllocType Type) {
     // For a deallocation, we only ensure minimal initialization, meaning thread
     // local data will be left uninitialized for now (when using ELF TLS). The
     // fallback cache will be used instead. This is a workaround for a situation
@@ -513,6 +514,7 @@ struct ScudoAllocator {
         dieWithMessage("invalid sized delete when deallocating address %p\n",
                        Ptr);
     }
+    (void)DeleteAlignment;  // TODO(kostyak): verify that the alignment matches.
     quarantineOrDeallocateChunk(Ptr, &Header, Size);
   }
 
@@ -627,23 +629,23 @@ void ScudoTSD::commitBack() {
   Instance.commitBack(this);
 }
 
-void *scudoMalloc(uptr Size, AllocType Type) {
-  return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, Type));
-}
-
-void scudoFree(void *Ptr, AllocType Type) {
-  Instance.deallocate(Ptr, 0, Type);
+void *scudoAllocate(uptr Size, uptr Alignment, AllocType Type) {
+  if (Alignment && UNLIKELY(!IsPowerOfTwo(Alignment))) {
+    errno = EINVAL;
+    return Instance.handleBadRequest();
+  }
+  return SetErrnoOnNull(Instance.allocate(Size, Alignment, Type));
 }
 
-void scudoSizedFree(void *Ptr, uptr Size, AllocType Type) {
-  Instance.deallocate(Ptr, Size, Type);
+void scudoDeallocate(void *Ptr, uptr Size, uptr Alignment, AllocType Type) {
+  Instance.deallocate(Ptr, Size, Alignment, Type);
 }
 
 void *scudoRealloc(void *Ptr, uptr Size) {
   if (!Ptr)
     return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, FromMalloc));
   if (Size == 0) {
-    Instance.deallocate(Ptr, 0, FromMalloc);
+    Instance.deallocate(Ptr, 0, 0, FromMalloc);
     return nullptr;
   }
   return SetErrnoOnNull(Instance.reallocate(Ptr, Size));
@@ -669,14 +671,6 @@ void *scudoPvalloc(uptr Size) {
   return SetErrnoOnNull(Instance.allocate(Size, PageSize, FromMemalign));
 }
 
-void *scudoMemalign(uptr Alignment, uptr Size) {
-  if (UNLIKELY(!IsPowerOfTwo(Alignment))) {
-    errno = EINVAL;
-    return Instance.handleBadRequest();
-  }
-  return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMemalign));
-}
-
 int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) {
   if (UNLIKELY(!CheckPosixMemalignAlignment(Alignment))) {
     Instance.handleBadRequest();

Modified: compiler-rt/trunk/lib/scudo/scudo_allocator.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_allocator.h?rev=334505&r1=334504&r2=334505&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_allocator.h (original)
+++ compiler-rt/trunk/lib/scudo/scudo_allocator.h Tue Jun 12 07:42:40 2018
@@ -115,12 +115,10 @@ typedef ScudoCombinedAllocator<PrimaryAl
 
 void initScudo();
 
-void *scudoMalloc(uptr Size, AllocType Type);
-void scudoFree(void *Ptr, AllocType Type);
-void scudoSizedFree(void *Ptr, uptr Size, AllocType Type);
+void *scudoAllocate(uptr Size, uptr Alignment, AllocType Type);
+void scudoDeallocate(void *Ptr, uptr Size, uptr Alignment, AllocType Type);
 void *scudoRealloc(void *Ptr, uptr Size);
 void *scudoCalloc(uptr NMemB, uptr Size);
-void *scudoMemalign(uptr Alignment, uptr Size);
 void *scudoValloc(uptr Size);
 void *scudoPvalloc(uptr Size);
 int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size);

Modified: compiler-rt/trunk/lib/scudo/scudo_malloc.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_malloc.cpp?rev=334505&r1=334504&r2=334505&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_malloc.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_malloc.cpp Tue Jun 12 07:42:40 2018
@@ -20,11 +20,11 @@ using namespace __scudo;
 
 extern "C" {
 INTERCEPTOR_ATTRIBUTE void free(void *ptr) {
-  scudoFree(ptr, FromMalloc);
+  scudoDeallocate(ptr, 0, 0, FromMalloc);
 }
 
 INTERCEPTOR_ATTRIBUTE void *malloc(SIZE_T size) {
-  return scudoMalloc(size, FromMalloc);
+  return scudoAllocate(size, 0, FromMalloc);
 }
 
 INTERCEPTOR_ATTRIBUTE void *realloc(void *ptr, SIZE_T size) {
@@ -50,7 +50,7 @@ INTERCEPTOR_ATTRIBUTE void cfree(void *p
 
 #if SANITIZER_INTERCEPT_MEMALIGN
 INTERCEPTOR_ATTRIBUTE void *memalign(SIZE_T alignment, SIZE_T size) {
-  return scudoMemalign(alignment, size);
+  return scudoAllocate(size, alignment, FromMemalign);
 }
 
 INTERCEPTOR_ATTRIBUTE

Modified: compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp?rev=334505&r1=334504&r2=334505&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp Tue Jun 12 07:42:40 2018
@@ -24,51 +24,84 @@ using namespace __scudo;
 // Fake std::nothrow_t to avoid including <new>.
 namespace std {
 struct nothrow_t {};
+enum class align_val_t: size_t {};
 }  // namespace std
 
 // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY_ALIGN(Type, Align, NoThrow)              \
+  void *Ptr = scudoAllocate(size, static_cast<uptr>(Align), Type); \
+  if (!NoThrow && UNLIKELY(!Ptr)) DieOnFailure::OnOOM();           \
+  return Ptr;
+#define OPERATOR_NEW_BODY(Type, NoThrow) \
+  OPERATOR_NEW_BODY_ALIGN(Type, 0, NoThrow)
+
+CXX_OPERATOR_ATTRIBUTE
+void *operator new(size_t size)
+{ OPERATOR_NEW_BODY(FromNew, /*NoThrow=*/false); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size)
+{ OPERATOR_NEW_BODY(FromNewArray, /*NoThrow=*/false); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new(size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(FromNew, /*NoThrow=*/true); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(FromNewArray, /*NoThrow=*/true); }
 CXX_OPERATOR_ATTRIBUTE
-void *operator new(size_t size) {
-  void *res = scudoMalloc(size, FromNew);
-  if (UNLIKELY(!res)) DieOnFailure::OnOOM();
-  return res;
-}
-CXX_OPERATOR_ATTRIBUTE
-void *operator new[](size_t size) {
-  void *res = scudoMalloc(size, FromNewArray);
-  if (UNLIKELY(!res)) DieOnFailure::OnOOM();
-  return res;
-}
-CXX_OPERATOR_ATTRIBUTE
-void *operator new(size_t size, std::nothrow_t const&) {
-  return scudoMalloc(size, FromNew);
-}
-CXX_OPERATOR_ATTRIBUTE
-void *operator new[](size_t size, std::nothrow_t const&) {
-  return scudoMalloc(size, FromNewArray);
-}
+void *operator new(size_t size, std::align_val_t align)
+{ OPERATOR_NEW_BODY_ALIGN(FromNew, align, /*NoThrow=*/false); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size, std::align_val_t align)
+{ OPERATOR_NEW_BODY_ALIGN(FromNewArray, align, /*NoThrow=*/false); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY_ALIGN(FromNew, align, /*NoThrow=*/true); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY_ALIGN(FromNewArray, align, /*NoThrow=*/true); }
 
+#define OPERATOR_DELETE_BODY(Type) \
+  scudoDeallocate(ptr, 0, 0, Type);
+#define OPERATOR_DELETE_BODY_SIZE(Type) \
+  scudoDeallocate(ptr, size, 0, Type);
+#define OPERATOR_DELETE_BODY_ALIGN(Type) \
+  scudoDeallocate(ptr, 0, static_cast<uptr>(align), Type);
+#define OPERATOR_DELETE_BODY_SIZE_ALIGN(Type) \
+  scudoDeallocate(ptr, size, static_cast<uptr>(align), Type);
+
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr) NOEXCEPT
+{ OPERATOR_DELETE_BODY(FromNew); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr) NOEXCEPT
+{ OPERATOR_DELETE_BODY(FromNewArray); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FromNew); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FromNewArray); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE(FromNew); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE(FromNewArray); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_ALIGN(FromNew); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_ALIGN(FromNewArray); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY_ALIGN(FromNew); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY_ALIGN(FromNewArray); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FromNew); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr) NOEXCEPT {
-  return scudoFree(ptr, FromNew);
-}
-CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr) NOEXCEPT {
-  return scudoFree(ptr, FromNewArray);
-}
-CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, std::nothrow_t const&) NOEXCEPT {
-  return scudoFree(ptr, FromNew);
-}
-CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, std::nothrow_t const&) NOEXCEPT {
-  return scudoFree(ptr, FromNewArray);
-}
-CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, size_t size) NOEXCEPT {
-  scudoSizedFree(ptr, size, FromNew);
-}
-CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, size_t size) NOEXCEPT {
-  scudoSizedFree(ptr, size, FromNewArray);
-}
+void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FromNewArray); }

Added: compiler-rt/trunk/test/scudo/aligned-new.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/scudo/aligned-new.cpp?rev=334505&view=auto
==============================================================================
--- compiler-rt/trunk/test/scudo/aligned-new.cpp (added)
+++ compiler-rt/trunk/test/scudo/aligned-new.cpp Tue Jun 12 07:42:40 2018
@@ -0,0 +1,84 @@
+// RUN: %clangxx_scudo -std=c++1z -faligned-allocation %s -o %t
+// RUN:                                             %run %t valid   2>&1
+// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1
+
+// Tests that the C++17 aligned new/delete operators are working as expected.
+// Currently we do not check the consistency of the alignment on deallocation,
+// so this just tests that the APIs work.
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+// Define all new/delete to not depend on the version provided by the platform.
+
+namespace std {
+struct nothrow_t {};
+static const nothrow_t nothrow;
+enum class align_val_t : size_t {};
+}  // namespace std
+
+void *operator new(size_t);
+void *operator new[](size_t);
+void *operator new(size_t, std::nothrow_t const&);
+void *operator new[](size_t, std::nothrow_t const&);
+void *operator new(size_t, std::align_val_t);
+void *operator new[](size_t, std::align_val_t);
+void *operator new(size_t, std::align_val_t, std::nothrow_t const&);
+void *operator new[](size_t, std::align_val_t, std::nothrow_t const&);
+
+void operator delete(void*) throw();
+void operator delete[](void*) throw();
+void operator delete(void*, std::nothrow_t const&);
+void operator delete[](void*, std::nothrow_t const&);
+void operator delete(void*, size_t) throw();
+void operator delete[](void*, size_t) throw();
+void operator delete(void*, std::align_val_t) throw();
+void operator delete[](void*, std::align_val_t) throw();
+void operator delete(void*, std::align_val_t, std::nothrow_t const&);
+void operator delete[](void*, std::align_val_t, std::nothrow_t const&);
+void operator delete(void*, size_t, std::align_val_t) throw();
+void operator delete[](void*, size_t, std::align_val_t) throw();
+
+template<typename T>
+inline T* break_optimization(T *arg) {
+  __asm__ __volatile__("" : : "r" (arg) : "memory");
+  return arg;
+}
+
+struct S12 { int a, b, c; };
+struct alignas(128) S12_128 { int a, b, c; };
+struct alignas(256) S12_256 { int a, b, c; };
+struct alignas(512) S1024_512 { char a[1024]; };
+struct alignas(1024) S1024_1024 { char a[1024]; };
+
+int main(int argc, char **argv) {
+  assert(argc == 2);
+
+  if (!strcmp(argv[1], "valid")) {
+    // Standard use case.
+    delete break_optimization(new S12);
+    delete break_optimization(new S12_128);
+    delete[] break_optimization(new S12_128[4]);
+    delete break_optimization(new S12_256);
+    delete break_optimization(new S1024_512);
+    delete[] break_optimization(new S1024_512[4]);
+    delete break_optimization(new S1024_1024);
+
+    // Call directly the aligned versions of the operators.
+    const size_t alignment = 1U << 8;
+    void *p = operator new(1, static_cast<std::align_val_t>(alignment));
+    assert((reinterpret_cast<uintptr_t>(p) & (alignment - 1)) == 0);
+    operator delete(p, static_cast<std::align_val_t>(alignment));
+  }
+  if (!strcmp(argv[1], "invalid")) {
+    // Alignment must be a power of 2.
+    const size_t alignment = (1U << 8) - 1;
+    void *p = operator new(1, static_cast<std::align_val_t>(alignment),
+                           std::nothrow);
+    assert(!p);
+  }
+
+  return 0;
+}




More information about the llvm-commits mailing list