[hwasan] Fix new[] with zero size.
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Fri, 31 Aug 2018 17:49:49 +0000 (17:49 +0000)
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Fri, 31 Aug 2018 17:49:49 +0000 (17:49 +0000)
Fixes "allocator is out of memory trying to allocate 0x0 bytes" by
always allocating at least one byte.

llvm-svn: 341229

compiler-rt/lib/hwasan/hwasan_allocator.cc
compiler-rt/test/hwasan/TestCases/malloc-test.c
compiler-rt/test/hwasan/TestCases/new-test.cc [new file with mode: 0644]

index 374cd70..a380d8d 100644 (file)
@@ -64,11 +64,15 @@ void HwasanThreadLocalMallocStorage::CommitBack() {
   allocator.SwallowCache(GetAllocatorCache(this));
 }
 
+static uptr TaggedSize(uptr size) {
+  if (!size) size = 1;
+  return RoundUpTo(size, kShadowAlignment);
+}
+
 static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
                             bool zeroise) {
-  if (!orig_size) return nullptr;
   alignment = Max(alignment, kShadowAlignment);
-  uptr size = RoundUpTo(orig_size, kShadowAlignment);
+  uptr size = TaggedSize(orig_size);
 
   if (size > kMaxAllowedMallocSize) {
     if (AllocatorMayReturnNull()) {
@@ -134,7 +138,7 @@ void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
   void *untagged_ptr = UntagPtr(tagged_ptr);
   Metadata *meta =
       reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr));
-  uptr size = meta->requested_size;
+  uptr orig_size = meta->requested_size;
   u32 free_context_id = StackDepotPut(*stack);
   u32 alloc_context_id = meta->alloc_context_id;
   meta->requested_size = 0;
@@ -143,19 +147,19 @@ void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
   // poisoned.
   Thread *t = GetCurrentThread();
   if (flags()->max_free_fill_size > 0) {
-    uptr fill_size = Min(size, (uptr)flags()->max_free_fill_size);
+    uptr fill_size = Min(orig_size, (uptr)flags()->max_free_fill_size);
     internal_memset(untagged_ptr, flags()->free_fill_byte, fill_size);
   }
   if (flags()->tag_in_free &&
       atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
-    TagMemoryAligned((uptr)untagged_ptr, RoundUpTo(size, kShadowAlignment),
+    TagMemoryAligned((uptr)untagged_ptr, TaggedSize(orig_size),
                      t ? t->GenerateRandomTag() : kFallbackFreeTag);
   if (t) {
     AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
     allocator.Deallocate(cache, untagged_ptr);
     if (auto *ha = t->heap_allocations())
       ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id,
-                free_context_id, static_cast<u32>(size)});
+                free_context_id, static_cast<u32>(orig_size)});
   } else {
     SpinMutexLock l(&fallback_mutex);
     AllocatorCache *cache = &fallback_allocator_cache;
@@ -165,9 +169,6 @@ void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
 
 void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, uptr new_size,
                      uptr alignment) {
-  alignment = Max(alignment, kShadowAlignment);
-  new_size = RoundUpTo(new_size, kShadowAlignment);
-
   if (!PointerAndMemoryTagsMatch(tagged_ptr_old))
     ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr_old));
 
index 13d04e6..199464b 100644 (file)
@@ -5,9 +5,12 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <sanitizer/hwasan_interface.h>
+#include <sanitizer/allocator_interface.h>
 
 int main() {
   __hwasan_enable_allocator_tagging();
   char *a1 = (char*)malloc(0);
-  assert(a1 == NULL);  // may not be true for other malloc.
+  assert(a1 != 0);
+  assert(__sanitizer_get_allocated_size(a1) == 0);
+  free(a1);
 }
diff --git a/compiler-rt/test/hwasan/TestCases/new-test.cc b/compiler-rt/test/hwasan/TestCases/new-test.cc
new file mode 100644 (file)
index 0000000..3b1991e
--- /dev/null
@@ -0,0 +1,18 @@
+// Test basic new functionality.
+// RUN: %clangxx_hwasan %s -o %t
+// RUN: %run %t
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sanitizer/hwasan_interface.h>
+#include <sanitizer/allocator_interface.h>
+
+int main() {
+  __hwasan_enable_allocator_tagging();
+
+  size_t volatile n = 0;
+  char *a1 = new char[n];
+  assert(a1 != nullptr);
+  assert(__sanitizer_get_allocated_size(a1) == 0);
+  delete[] a1;
+}