[PATCH] D17690: [asan] Check if the memory is readable before using the AsanChunk in free() and realloc()

Filipe Cabecinhas via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 28 01:39:32 PST 2016


filcab created this revision.
filcab added reviewers: kcc, samsonov, earthdok.
filcab added a subscriber: llvm-commits.

This allows us to better diagnose free() and realloc() with a bad
pointer, instead of SIGSEGV.

http://reviews.llvm.org/D17690

Files:
  lib/asan/asan_allocator.cc
  test/asan/TestCases/Posix/bad-free-no-segv.cc

Index: test/asan/TestCases/Posix/bad-free-no-segv.cc
===================================================================
--- /dev/null
+++ test/asan/TestCases/Posix/bad-free-no-segv.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t f 2>&1 | FileCheck %s
+// RUN: not %run %t r 2>&1 | FileCheck %s
+#include <assert.h>
+#include <stdlib.h>
+#include <sanitizer/asan_interface.h>
+
+// CHECK-NOT: DEADLYSIGNAL
+// CHECK: AddressSanitizer: attempting free on address which was not malloc()-ed
+int main(int argc, char **argv) {
+  // The shadow gap is mprotect()ed, so we get an address inside it and pass it
+  // along to free. reading from it should be a problem and ASan should notice
+  // it before trying to read.
+  size_t shadow_scale, shadow_offset;
+  __asan_get_shadow_mapping(&shadow_scale, &shadow_offset);
+  // We add 0x100 because asan_free subtracts sizeof(AsanChunk) to our ptr.
+  // Which means we need to make sure that the free()ed/realloc()ed pointer is
+  // also in non-addressable memory.
+  void *p = (void *)(shadow_offset + 0x1000 + (shadow_offset >> shadow_scale));
+  assert(argc == 2);
+  switch (argv[1][0]) {
+  case 'f':
+    free(p);
+    break;
+  case 'r':
+    realloc(p, 42);
+    break;
+  default:
+    assert(false);
+  }
+}
Index: lib/asan/asan_allocator.cc
===================================================================
--- lib/asan/asan_allocator.cc
+++ lib/asan/asan_allocator.cc
@@ -22,6 +22,7 @@
 #include "asan_stack.h"
 #include "asan_thread.h"
 #include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_list.h"
@@ -523,6 +524,8 @@
 
     uptr chunk_beg = p - kChunkHeaderSize;
     AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+    if (!IsAccessibleMemoryRange((uptr)m, sizeof(AsanChunk)))
+      ReportFreeNotMalloced((uptr)ptr, stack);
     if (delete_size && flags()->new_delete_type_mismatch &&
         delete_size != m->UsedSize()) {
       ReportNewDeleteSizeMismatch(p, delete_size, stack);
@@ -539,6 +542,8 @@
     uptr p = reinterpret_cast<uptr>(old_ptr);
     uptr chunk_beg = p - kChunkHeaderSize;
     AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+    if (!IsAccessibleMemoryRange((uptr)m, sizeof(AsanChunk)))
+      ReportFreeNotMalloced((uptr)old_ptr, stack);
 
     AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.reallocs++;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D17690.49313.patch
Type: text/x-patch
Size: 2559 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160228/9bf37c48/attachment.bin>


More information about the llvm-commits mailing list