[compiler-rt] r316595 - [Sanitizers] ASan: detect new/delete calls with mismatched alignment.

Alex Shlyapnikov via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 25 10:21:37 PDT 2017


Author: alekseyshl
Date: Wed Oct 25 10:21:37 2017
New Revision: 316595

URL: http://llvm.org/viewvc/llvm-project?rev=316595&view=rev
Log:
[Sanitizers] ASan: detect new/delete calls with mismatched alignment.

ASan allocator stores the requested alignment for new and new[] calls
and on delete and delete[] verifies that alignments do match.

The representable alignments are: default alignment, 8, 16, 32, 64, 128,
256 and 512 bytes. Alignments > 512 are stored as 512, hence two
different alignments > 512 will pass the check (possibly masking the bug),
but limited memory requirements deemed to be a resonable tradeoff for
relaxed conditions.

The feature is controlled by new_delete_type_mismatch flag, the same one
protecting new/delete matching size check.

Differential revision: https://reviews.llvm.org/D38574

Issue: https://github.com/google/sanitizers/issues/799

Added:
    compiler-rt/trunk/test/asan/TestCases/Linux/aligned_delete_test.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_allocator.cc
    compiler-rt/trunk/lib/asan/asan_allocator.h
    compiler-rt/trunk/lib/asan/asan_descriptions.cc
    compiler-rt/trunk/lib/asan/asan_descriptions.h
    compiler-rt/trunk/lib/asan/asan_errors.cc
    compiler-rt/trunk/lib/asan/asan_errors.h
    compiler-rt/trunk/lib/asan/asan_new_delete.cc
    compiler-rt/trunk/lib/asan/asan_report.cc
    compiler-rt/trunk/lib/asan/asan_report.h

Modified: compiler-rt/trunk/lib/asan/asan_allocator.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator.cc?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_allocator.cc Wed Oct 25 10:21:37 2017
@@ -84,7 +84,10 @@ struct ChunkHeader {
   // This field is used for small sizes. For large sizes it is equal to
   // SizeClassMap::kMaxSize and the actual size is stored in the
   // SecondaryAllocator's metadata.
-  u32 user_requested_size;
+  u32 user_requested_size : 29;
+  // align < 8 -> 0
+  // else      -> log2(min(align, 512)) - 2
+  u32 user_requested_alignment_log : 3;
   u32 alloc_context_id;
 };
 
@@ -351,6 +354,20 @@ struct Allocator {
     return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz));
   }
 
+  static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) {
+    if (user_requested_alignment < 8)
+      return 0;
+    if (user_requested_alignment > 512)
+      user_requested_alignment = 512;
+    return Log2(user_requested_alignment) - 2;
+  }
+
+  static uptr ComputeUserAlignment(uptr user_requested_alignment_log) {
+    if (user_requested_alignment_log == 0)
+      return 0;
+    return 1LL << (user_requested_alignment_log + 2);
+  }
+
   // We have an address between two chunks, and we want to report just one.
   AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk,
                          AsanChunk *right_chunk) {
@@ -385,6 +402,8 @@ struct Allocator {
     Flags &fl = *flags();
     CHECK(stack);
     const uptr min_alignment = SHADOW_GRANULARITY;
+    const uptr user_requested_alignment_log =
+        ComputeUserRequestedAlignmentLog(alignment);
     if (alignment < min_alignment)
       alignment = min_alignment;
     if (size == 0) {
@@ -472,6 +491,7 @@ struct Allocator {
       meta[0] = size;
       meta[1] = chunk_beg;
     }
+    m->user_requested_alignment_log = user_requested_alignment_log;
 
     m->alloc_context_id = StackDepotPut(*stack);
 
@@ -573,8 +593,8 @@ struct Allocator {
     }
   }
 
-  void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
-                  AllocType alloc_type) {
+  void Deallocate(void *ptr, uptr delete_size, uptr delete_alignment,
+                  BufferedStackTrace *stack, AllocType alloc_type) {
     uptr p = reinterpret_cast<uptr>(ptr);
     if (p == 0) return;
 
@@ -601,11 +621,14 @@ struct Allocator {
         ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
                                 (AllocType)alloc_type);
       }
-    }
-
-    if (delete_size && flags()->new_delete_type_mismatch &&
-        delete_size != m->UsedSize()) {
-      ReportNewDeleteSizeMismatch(p, delete_size, stack);
+    } else {
+      if (flags()->new_delete_type_mismatch &&
+          (alloc_type == FROM_NEW || alloc_type == FROM_NEW_BR) &&
+          ((delete_size && delete_size != m->UsedSize()) ||
+           ComputeUserRequestedAlignmentLog(delete_alignment) !=
+               m->user_requested_alignment_log)) {
+        ReportNewDeleteTypeMismatch(p, delete_size, delete_alignment, stack);
+      }
     }
 
     QuarantineChunk(m, ptr, stack);
@@ -631,7 +654,7 @@ struct Allocator {
       // If realloc() races with free(), we may start copying freed memory.
       // However, we will report racy double-free later anyway.
       REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
-      Deallocate(old_ptr, 0, stack, FROM_MALLOC);
+      Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC);
     }
     return new_ptr;
   }
@@ -766,6 +789,9 @@ bool AsanChunkView::IsQuarantined() cons
 uptr AsanChunkView::Beg() const { return chunk_->Beg(); }
 uptr AsanChunkView::End() const { return Beg() + UsedSize(); }
 uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); }
+u32 AsanChunkView::UserRequestedAlignment() const {
+  return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log);
+}
 uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; }
 uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; }
 AllocType AsanChunkView::GetAllocType() const {
@@ -818,12 +844,12 @@ void PrintInternalAllocatorStats() {
 }
 
 void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
-  instance.Deallocate(ptr, 0, stack, alloc_type);
+  instance.Deallocate(ptr, 0, 0, stack, alloc_type);
 }
 
-void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
-                     AllocType alloc_type) {
-  instance.Deallocate(ptr, size, stack, alloc_type);
+void asan_delete(void *ptr, uptr size, uptr alignment,
+                 BufferedStackTrace *stack, AllocType alloc_type) {
+  instance.Deallocate(ptr, size, alignment, stack, alloc_type);
 }
 
 void *asan_malloc(uptr size, BufferedStackTrace *stack) {
@@ -839,7 +865,7 @@ void *asan_realloc(void *p, uptr size, B
     return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true));
   if (size == 0) {
     if (flags()->allocator_frees_and_returns_null_on_realloc_zero) {
-      instance.Deallocate(p, 0, stack, FROM_MALLOC);
+      instance.Deallocate(p, 0, 0, stack, FROM_MALLOC);
       return nullptr;
     }
     // Allocate a size of 1 if we shouldn't free() on Realloc to 0

Modified: compiler-rt/trunk/lib/asan/asan_allocator.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator.h?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator.h (original)
+++ compiler-rt/trunk/lib/asan/asan_allocator.h Wed Oct 25 10:21:37 2017
@@ -58,6 +58,7 @@ class AsanChunkView {
   uptr Beg() const;            // First byte of user memory.
   uptr End() const;            // Last byte of user memory.
   uptr UsedSize() const;       // Size requested by the user.
+  u32 UserRequestedAlignment() const;  // Originally requested alignment.
   uptr AllocTid() const;
   uptr FreeTid() const;
   bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
@@ -197,8 +198,8 @@ struct AsanThreadLocalMallocStorage {
 void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
                     AllocType alloc_type);
 void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
-void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
-                     AllocType alloc_type);
+void asan_delete(void *ptr, uptr size, uptr alignment,
+                 BufferedStackTrace *stack, AllocType alloc_type);
 
 void *asan_malloc(uptr size, BufferedStackTrace *stack);
 void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);

Modified: compiler-rt/trunk/lib/asan/asan_descriptions.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_descriptions.cc?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_descriptions.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_descriptions.cc Wed Oct 25 10:21:37 2017
@@ -122,6 +122,7 @@ static void GetAccessToHeapChunkInformat
   }
   descr->chunk_begin = chunk.Beg();
   descr->chunk_size = chunk.UsedSize();
+  descr->user_requested_alignment = chunk.UserRequestedAlignment();
   descr->alloc_type = chunk.GetAllocType();
 }
 

Modified: compiler-rt/trunk/lib/asan/asan_descriptions.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_descriptions.h?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_descriptions.h (original)
+++ compiler-rt/trunk/lib/asan/asan_descriptions.h Wed Oct 25 10:21:37 2017
@@ -102,6 +102,7 @@ struct ChunkAccess {
   sptr offset;
   uptr chunk_begin;
   uptr chunk_size;
+  u32 user_requested_alignment : 12;
   u32 access_type : 2;
   u32 alloc_type : 2;
 };

Modified: compiler-rt/trunk/lib/asan/asan_errors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_errors.cc?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_errors.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_errors.cc Wed Oct 25 10:21:37 2017
@@ -63,7 +63,7 @@ void ErrorDoubleFree::Print() {
   ReportErrorSummary(scariness.GetDescription(), &stack);
 }
 
-void ErrorNewDeleteSizeMismatch::Print() {
+void ErrorNewDeleteTypeMismatch::Print() {
   Decorator d;
   Printf("%s", d.Warning());
   char tname[128];
@@ -73,10 +73,28 @@ void ErrorNewDeleteSizeMismatch::Print()
       scariness.GetDescription(), addr_description.addr, tid,
       ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
   Printf("%s  object passed to delete has wrong type:\n", d.Default());
-  Printf(
-      "  size of the allocated type:   %zd bytes;\n"
-      "  size of the deallocated type: %zd bytes.\n",
-      addr_description.chunk_access.chunk_size, delete_size);
+  if (delete_size != 0) {
+    Printf(
+        "  size of the allocated type:   %zd bytes;\n"
+        "  size of the deallocated type: %zd bytes.\n",
+        addr_description.chunk_access.chunk_size, delete_size);
+  }
+  const uptr user_alignment =
+      addr_description.chunk_access.user_requested_alignment;
+  if (delete_alignment != user_alignment) {
+    char user_alignment_str[32];
+    char delete_alignment_str[32];
+    internal_snprintf(user_alignment_str, sizeof(user_alignment_str),
+                      "%zd bytes", user_alignment);
+    internal_snprintf(delete_alignment_str, sizeof(delete_alignment_str),
+                      "%zd bytes", delete_alignment);
+    static const char *kDefaultAlignment = "default-aligned";
+    Printf(
+        "  alignment of the allocated type:   %s;\n"
+        "  alignment of the deallocated type: %s.\n",
+        user_alignment > 0 ? user_alignment_str : kDefaultAlignment,
+        delete_alignment > 0 ? delete_alignment_str : kDefaultAlignment);
+  }
   CHECK_GT(free_stack->size, 0);
   scariness.Print();
   GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);

Modified: compiler-rt/trunk/lib/asan/asan_errors.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_errors.h?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_errors.h (original)
+++ compiler-rt/trunk/lib/asan/asan_errors.h Wed Oct 25 10:21:37 2017
@@ -71,17 +71,19 @@ struct ErrorDoubleFree : ErrorBase {
   void Print();
 };
 
-struct ErrorNewDeleteSizeMismatch : ErrorBase {
-  // ErrorNewDeleteSizeMismatch doesn't own the stack trace.
+struct ErrorNewDeleteTypeMismatch : ErrorBase {
+  // ErrorNewDeleteTypeMismatch doesn't own the stack trace.
   const BufferedStackTrace *free_stack;
   HeapAddressDescription addr_description;
   uptr delete_size;
+  uptr delete_alignment;
   // VS2013 doesn't implement unrestricted unions, so we need a trivial default
   // constructor
-  ErrorNewDeleteSizeMismatch() = default;
-  ErrorNewDeleteSizeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
-                             uptr delete_size_)
-      : ErrorBase(tid), free_stack(stack), delete_size(delete_size_) {
+  ErrorNewDeleteTypeMismatch() = default;
+  ErrorNewDeleteTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
+                             uptr delete_size_, uptr delete_alignment_)
+      : ErrorBase(tid), free_stack(stack), delete_size(delete_size_),
+        delete_alignment(delete_alignment_) {
     GetHeapAddressInformation(addr, 1, &addr_description);
     scariness.Clear();
     scariness.Scare(10, "new-delete-type-mismatch");
@@ -293,7 +295,7 @@ struct ErrorGeneric : ErrorBase {
 #define ASAN_FOR_EACH_ERROR_KIND(macro)         \
   macro(DeadlySignal)                           \
   macro(DoubleFree)                             \
-  macro(NewDeleteSizeMismatch)                  \
+  macro(NewDeleteTypeMismatch)                  \
   macro(FreeNotMalloced)                        \
   macro(AllocTypeMismatch)                      \
   macro(MallocUsableSizeNotOwned)               \

Modified: compiler-rt/trunk/lib/asan/asan_new_delete.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_new_delete.cc?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_new_delete.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_new_delete.cc Wed Oct 25 10:21:37 2017
@@ -125,77 +125,69 @@ INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t,
 INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
   OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
 }
-#endif
+#endif  // !SANITIZER_MAC
 
 #define OPERATOR_DELETE_BODY(type) \
   GET_STACK_TRACE_FREE;\
-  asan_free(ptr, &stack, type);
+  asan_delete(ptr, 0, 0, &stack, type);
+
+#define OPERATOR_DELETE_BODY_SIZE(type) \
+  GET_STACK_TRACE_FREE;\
+  asan_delete(ptr, size, 0, &stack, type);
+
+#define OPERATOR_DELETE_BODY_ALIGN(type) \
+  GET_STACK_TRACE_FREE;\
+  asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type);
+
+#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \
+  GET_STACK_TRACE_FREE;\
+  asan_delete(ptr, size, static_cast<uptr>(align), &stack, type);
 
 #if !SANITIZER_MAC
 CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr) NOEXCEPT {
-  OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr) NOEXCEPT
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr) NOEXCEPT {
-  OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr) NOEXCEPT
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, std::nothrow_t const&) {
-  OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, std::nothrow_t const&) {
-  OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, size_t size) NOEXCEPT {
-  GET_STACK_TRACE_FREE;
-  asan_sized_free(ptr, size, &stack, FROM_NEW);
-}
+void operator delete(void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, size_t size) NOEXCEPT {
-  GET_STACK_TRACE_FREE;
-  asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
-}
+void operator delete[](void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, std::align_val_t) NOEXCEPT {
-  OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, std::align_val_t) NOEXCEPT {
-  OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&) {
-  OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) {
-  OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT {
-  GET_STACK_TRACE_FREE;
-  asan_sized_free(ptr, size, &stack, FROM_NEW);
-}
+void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); }
 CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT {
-  GET_STACK_TRACE_FREE;
-  asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
-}
+void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); }
 
 #else  // SANITIZER_MAC
-INTERCEPTOR(void, _ZdlPv, void *ptr) {
-  OPERATOR_DELETE_BODY(FROM_NEW);
-}
-INTERCEPTOR(void, _ZdaPv, void *ptr) {
-  OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
-INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
-  OPERATOR_DELETE_BODY(FROM_NEW);
-}
-INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
-  OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
-#endif
+INTERCEPTOR(void, _ZdlPv, void *ptr)
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
+INTERCEPTOR(void, _ZdaPv, void *ptr)
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
+INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
+INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
+#endif  // !SANITIZER_MAC

Modified: compiler-rt/trunk/lib/asan/asan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.cc?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_report.cc Wed Oct 25 10:21:37 2017
@@ -216,11 +216,12 @@ void ReportDoubleFree(uptr addr, Buffere
   in_report.ReportError(error);
 }
 
-void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
+                                 uptr delete_alignment,
                                  BufferedStackTrace *free_stack) {
   ScopedInErrorReport in_report;
-  ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
-                                   delete_size);
+  ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
+                                   delete_size, delete_alignment);
   in_report.ReportError(error);
 }
 

Modified: compiler-rt/trunk/lib/asan/asan_report.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.h?rev=316595&r1=316594&r2=316595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.h (original)
+++ compiler-rt/trunk/lib/asan/asan_report.h Wed Oct 25 10:21:37 2017
@@ -47,7 +47,8 @@ bool ParseFrameDescription(const char *f
 void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
                         uptr access_size, u32 exp, bool fatal);
 void ReportDeadlySignal(const SignalContext &sig);
-void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
+                                 uptr delete_alignment,
                                  BufferedStackTrace *free_stack);
 void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
 void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);

Added: compiler-rt/trunk/test/asan/TestCases/Linux/aligned_delete_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/aligned_delete_test.cc?rev=316595&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Linux/aligned_delete_test.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Linux/aligned_delete_test.cc Wed Oct 25 10:21:37 2017
@@ -0,0 +1,168 @@
+// RUN: %clangxx_asan -std=c++1z -faligned-allocation -fsanitize-recover=address -O0 %s -o %t
+// RUN: %env_asan_opts=new_delete_type_mismatch=1:halt_on_error=false:detect_leaks=false %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=new_delete_type_mismatch=0                                        %run %t
+
+// RUN: %clangxx_asan -std=c++1z -faligned-allocation -fsized-deallocation -fsanitize-recover=address -O0 %s -o %t
+// RUN: %env_asan_opts=new_delete_type_mismatch=1:halt_on_error=false:detect_leaks=false %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=new_delete_type_mismatch=0                                        %run %t
+
+// REQUIRES: asan-static-runtime
+
+#include <stdio.h>
+
+// Define all new/delete to do not depend on the version provided by the
+// plaform. The implementation is provided by ASan anyway.
+
+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) {
+  fprintf(stderr, "Testing valid cases\n");
+
+  delete break_optimization(new S12);
+  operator delete(break_optimization(new S12), std::nothrow);
+  delete [] break_optimization(new S12[100]);
+  operator delete[](break_optimization(new S12[100]), std::nothrow);
+
+  delete break_optimization(new S12_128);
+  operator delete(break_optimization(new S12_128),
+                  std::align_val_t(alignof(S12_128)));
+  operator delete(break_optimization(new S12_128),
+                  std::align_val_t(alignof(S12_128)), std::nothrow);
+  operator delete(break_optimization(new S12_128), sizeof(S12_128),
+                  std::align_val_t(alignof(S12_128)));
+
+  delete [] break_optimization(new S12_128[100]);
+  operator delete[](break_optimization(new S12_128[100]),
+                    std::align_val_t(alignof(S12_128)));
+  operator delete[](break_optimization(new S12_128[100]),
+                    std::align_val_t(alignof(S12_128)), std::nothrow);
+  operator delete[](break_optimization(new S12_128[100]), sizeof(S12_128[100]),
+                    std::align_val_t(alignof(S12_128)));
+
+  fprintf(stderr, "Done\n");
+  // CHECK: Testing valid cases
+  // CHECK-NEXT: Done
+
+  // Explicit mismatched calls.
+
+  operator delete(break_optimization(new S12_128), std::nothrow);
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   128 bytes;
+  // CHECK:  alignment of the deallocated type: default-aligned.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  operator delete(break_optimization(new S12_128), sizeof(S12_128));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   128 bytes;
+  // CHECK:  alignment of the deallocated type: default-aligned.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  operator delete[](break_optimization(new S12_128[100]), std::nothrow);
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   128 bytes;
+  // CHECK:  alignment of the deallocated type: default-aligned.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  operator delete[](break_optimization(new S12_128[100]), sizeof(S12_128[100]));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   128 bytes;
+  // CHECK:  alignment of the deallocated type: default-aligned.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  // Various mismatched alignments.
+
+  delete break_optimization(reinterpret_cast<S12*>(new S12_256));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   256 bytes;
+  // CHECK:  alignment of the deallocated type: default-aligned.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  delete break_optimization(reinterpret_cast<S12_256*>(new S12));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   default-aligned;
+  // CHECK:  alignment of the deallocated type: 256 bytes.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  delete break_optimization(reinterpret_cast<S12_128*>(new S12_256));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   256 bytes;
+  // CHECK:  alignment of the deallocated type: 128 bytes.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  delete [] break_optimization(reinterpret_cast<S12*>(new S12_256[100]));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   256 bytes;
+  // CHECK:  alignment of the deallocated type: default-aligned.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  delete [] break_optimization(reinterpret_cast<S12_256*>(new S12[100]));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   default-aligned;
+  // CHECK:  alignment of the deallocated type: 256 bytes.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  delete [] break_optimization(reinterpret_cast<S12_128*>(new S12_256[100]));
+  // CHECK: AddressSanitizer: new-delete-type-mismatch
+  // CHECK:  object passed to delete has wrong type:
+  // CHECK:  alignment of the allocated type:   256 bytes;
+  // CHECK:  alignment of the deallocated type: 128 bytes.
+  // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+
+  // Push ASan limits, the current limitation is that it cannot differentiate
+  // alignments above 512 bytes.
+  fprintf(stderr, "Checking alignments >= 512 bytes\n");
+  delete break_optimization(reinterpret_cast<S1024_512*>(new S1024_1024));
+  fprintf(stderr, "Done\n");
+  // CHECK: Checking alignments >= 512 bytes
+  // CHECK-NEXT: Done
+}




More information about the llvm-commits mailing list