[compiler-rt] r254395 - [asan] Correctly release memory allocated during early startup.

Yury Gribov via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 1 01:22:42 PST 2015


Author: ygribov
Date: Tue Dec  1 03:22:41 2015
New Revision: 254395

URL: http://llvm.org/viewvc/llvm-project?rev=254395&view=rev
Log:
[asan] Correctly release memory allocated during early startup.

Calloc interceptor initially allocates memory from temp buffer (to serve dlsyms called during asan_init). There is a chance that some non-instrumented library (or executable) has allocated memory with calloc before asan_init and got pointer from the same temporary buffer which later caused problems with free.

Inspired by https://github.com/google/sanitizers/issues/626

Differential Revision: http://reviews.llvm.org/D14979

Added:
    compiler-rt/trunk/test/asan/TestCases/Linux/calloc-preload.c
Modified:
    compiler-rt/trunk/lib/asan/asan_malloc_linux.cc

Modified: compiler-rt/trunk/lib/asan/asan_malloc_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_malloc_linux.cc?rev=254395&r1=254394&r2=254395&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_malloc_linux.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_malloc_linux.cc Tue Dec  1 03:22:41 2015
@@ -26,13 +26,25 @@
 // ---------------------- Replacement functions ---------------- {{{1
 using namespace __asan;  // NOLINT
 
+static const uptr kCallocPoolSize = 1024;
+static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+
+static bool IsInCallocPool(const void *ptr) {
+  sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym;
+  return 0 <= off && off < (sptr)kCallocPoolSize;
+}
+
 INTERCEPTOR(void, free, void *ptr) {
   GET_STACK_TRACE_FREE;
+  if (UNLIKELY(IsInCallocPool(ptr)))
+    return;
   asan_free(ptr, &stack, FROM_MALLOC);
 }
 
 INTERCEPTOR(void, cfree, void *ptr) {
   GET_STACK_TRACE_FREE;
+  if (UNLIKELY(IsInCallocPool(ptr)))
+    return;
   asan_free(ptr, &stack, FROM_MALLOC);
 }
 
@@ -44,8 +56,6 @@ INTERCEPTOR(void*, malloc, uptr size) {
 INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
   if (UNLIKELY(!asan_inited)) {
     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
-    const uptr kCallocPoolSize = 1024;
-    static uptr calloc_memory_for_dlsym[kCallocPoolSize];
     static uptr allocated;
     uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
     void *mem = (void*)&calloc_memory_for_dlsym[allocated];
@@ -59,6 +69,13 @@ INTERCEPTOR(void*, calloc, uptr nmemb, u
 
 INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
   GET_STACK_TRACE_MALLOC;
+  if (UNLIKELY(IsInCallocPool(ptr))) {
+    uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym;
+    uptr copy_size = Min(size, kCallocPoolSize - offset);
+    void *new_ptr = asan_malloc(size, &stack);
+    internal_memcpy(new_ptr, ptr, copy_size);
+    return new_ptr;
+  }
   return asan_realloc(ptr, size, &stack);
 }
 

Added: compiler-rt/trunk/test/asan/TestCases/Linux/calloc-preload.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/calloc-preload.c?rev=254395&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Linux/calloc-preload.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/Linux/calloc-preload.c Tue Dec  1 03:22:41 2015
@@ -0,0 +1,36 @@
+// Test that initially callocked memory is properly freed
+// (see https://github.com/google/sanitizers/issues/626).
+// 
+// RUN: %clang %s -o %t
+// RUN: env LD_PRELOAD=%shared_libasan %run %t
+//
+// REQUIRES: asan-dynamic-runtime
+//
+// This way of setting LD_PRELOAD does not work with Android test runner.
+// REQUIRES: not-android
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void *ptr;
+
+// This constructor will run before __asan_init
+// so calloc will allocate memory from special pool.
+static void init() {
+  ptr = calloc(10, 1);
+}
+
+__attribute__((section(".preinit_array"), used))
+void *dummy = init;
+
+void free_memory() {
+  // This used to abort because
+  // Asan's free didn't recognize ptr.
+  free(ptr);
+}
+
+int main() {
+  free_memory();
+  return 0;
+}
+




More information about the llvm-commits mailing list