[PATCH] D14979: [asan] Correctly release memory allocated during early startup.
Yury Gribov via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 25 02:55:29 PST 2015
ygribov created this revision.
ygribov added reviewers: kcc, samsonov.
ygribov added subscribers: eugenis, dvyukov, llvm-commits.
ygribov set the repository for this revision to rL LLVM.
Herald added subscribers: srhines, danalbert, tberghammer.
Inspired by https://github.com/google/sanitizers/issues/626
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.
Repository:
rL LLVM
http://reviews.llvm.org/D14979
Files:
lib/asan/asan_malloc_linux.cc
test/asan/TestCases/Linux/calloc-preload.c
Index: test/asan/TestCases/Linux/calloc-preload.c
===================================================================
--- /dev/null
+++ test/asan/TestCases/Linux/calloc-preload.c
@@ -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;
+}
+
Index: lib/asan/asan_malloc_linux.cc
===================================================================
--- lib/asan/asan_malloc_linux.cc
+++ lib/asan/asan_malloc_linux.cc
@@ -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)calloc_memory_for_dlsym - (sptr)ptr;
+ return 0 <= off && off < (sptr)kCallocPoolSize;
+}
+
INTERCEPTOR(void, free, void *ptr) {
GET_STACK_TRACE_FREE;
+ if (IsInCallocPool(ptr))
+ return;
asan_free(ptr, &stack, FROM_MALLOC);
}
INTERCEPTOR(void, cfree, void *ptr) {
GET_STACK_TRACE_FREE;
+ if (IsInCallocPool(ptr))
+ return;
asan_free(ptr, &stack, FROM_MALLOC);
}
@@ -44,8 +56,6 @@
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*, realloc, void *ptr, uptr size) {
GET_STACK_TRACE_MALLOC;
+ if (IsInCallocPool(ptr)) {
+ uptr offset = (uptr)calloc_memory_for_dlsym - (uptr)ptr;
+ 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);
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D14979.41121.patch
Type: text/x-patch
Size: 2717 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20151125/ea08c124/attachment.bin>
More information about the llvm-commits
mailing list