From 8be1a6b6e3e21063db43fdceef1465d5c75d77ca Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 14 Mar 2014 20:31:13 -0400 Subject: [PATCH] Fix: liblttng-ust-libc-wrapper recursive use of calloc When built with URCU with --disable-compiler-tls, URCU tls-compat.h uses calloc in its TLS compat layer. This is used by RCU read-side, which is used by tracepoint. So using a tracepoint in calloc triggers an infinite recursion, since its first use of the TLS (with TLS compat) calls calloc. Fix this issue by keeping a per-thread nesting counter, and as soon as we are allocating memory from a context nested within the memory allocator, don't trace. Don't trace from the static allocator: keep it as simple as possible, since this is our fallback. Signed-off-by: Mathieu Desnoyers --- liblttng-ust-libc-wrapper/lttng-ust-malloc.c | 75 +++++++++++++++----- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/liblttng-ust-libc-wrapper/lttng-ust-malloc.c b/liblttng-ust-libc-wrapper/lttng-ust-malloc.c index 54522b42..06e0efe8 100644 --- a/liblttng-ust-libc-wrapper/lttng-ust-malloc.c +++ b/liblttng-ust-libc-wrapper/lttng-ust-malloc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define TRACEPOINT_DEFINE @@ -47,6 +48,18 @@ struct alloc_functions { static struct alloc_functions cur_alloc; +/* + * Make sure our own use of the LTS compat layer will not cause infinite + * recursion by calling calloc. + */ + +static +void *static_calloc(size_t nmemb, size_t size); + +#define calloc static_calloc +static DEFINE_URCU_TLS(int, malloc_nesting); +#undef calloc + /* * Static allocator to use when initially executing dlsym(). It keeps a * size_t value of each object size prior to the object. @@ -86,7 +99,6 @@ void *static_calloc(size_t nmemb, size_t size) void *retval; retval = static_calloc_aligned(nmemb, size, 1); - tracepoint(ust_libc, calloc, nmemb, size, retval); return retval; } @@ -96,7 +108,6 @@ void *static_malloc(size_t size) void *retval; retval = static_calloc_aligned(1, size, 1); - tracepoint(ust_libc, malloc, size, retval); return retval; } @@ -104,7 +115,6 @@ static void static_free(void *ptr) { /* no-op. */ - tracepoint(ust_libc, free, ptr); } static @@ -133,7 +143,6 @@ void *static_realloc(void *ptr, size_t size) if (ptr) memcpy(retval, ptr, *old_size); end: - tracepoint(ust_libc, realloc, ptr, size, retval); return retval; } @@ -143,29 +152,23 @@ void *static_memalign(size_t alignment, size_t size) void *retval; retval = static_calloc_aligned(1, size, alignment); - tracepoint(ust_libc, memalign, alignment, size, retval); return retval; } static int static_posix_memalign(void **memptr, size_t alignment, size_t size) { - int retval = 0; void *ptr; /* Check for power of 2, larger than void *. */ if (alignment & (alignment - 1) || alignment < sizeof(void *) || alignment == 0) { - retval = EINVAL; goto end; } ptr = static_calloc_aligned(1, size, alignment); *memptr = ptr; - if (size && !ptr) - retval = ENOMEM; end: - tracepoint(ust_libc, posix_memalign, *memptr, alignment, size, retval); return 0; } @@ -214,6 +217,7 @@ void *malloc(size_t size) { void *retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.malloc == NULL) { lookup_all_symbols(); if (cur_alloc.malloc == NULL) { @@ -222,21 +226,27 @@ void *malloc(size_t size) } } retval = cur_alloc.malloc(size); - tracepoint(ust_libc, malloc, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(ust_libc, malloc, size, retval); + } + URCU_TLS(malloc_nesting)--; return retval; } void free(void *ptr) { - tracepoint(ust_libc, free, ptr); - + URCU_TLS(malloc_nesting)++; /* * Check whether the memory was allocated with * static_calloc_align, in which case there is nothing to free. */ if (caa_unlikely((char *)ptr >= static_calloc_buf && (char *)ptr < static_calloc_buf + STATIC_CALLOC_LEN)) { - return; + goto end; + } + + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(ust_libc, free, ptr); } if (cur_alloc.free == NULL) { @@ -247,12 +257,15 @@ void free(void *ptr) } } cur_alloc.free(ptr); +end: + URCU_TLS(malloc_nesting)--; } void *calloc(size_t nmemb, size_t size) { void *retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.calloc == NULL) { lookup_all_symbols(); if (cur_alloc.calloc == NULL) { @@ -261,7 +274,10 @@ void *calloc(size_t nmemb, size_t size) } } retval = cur_alloc.calloc(nmemb, size); - tracepoint(ust_libc, calloc, nmemb, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(ust_libc, calloc, nmemb, size, retval); + } + URCU_TLS(malloc_nesting)--; return retval; } @@ -269,7 +285,9 @@ void *realloc(void *ptr, size_t size) { void *retval; - /* Check whether the memory was allocated with + URCU_TLS(malloc_nesting)++; + /* + * Check whether the memory was allocated with * static_calloc_align, in which case there is nothing * to free, and we need to copy the old data. */ @@ -289,6 +307,13 @@ void *realloc(void *ptr, size_t size) if (retval) { memcpy(retval, ptr, *old_size); } + /* + * Mimick that a NULL pointer has been received, so + * memory allocation analysis based on the trace don't + * get confused by the address from the static + * allocator. + */ + ptr = NULL; goto end; } @@ -301,7 +326,10 @@ void *realloc(void *ptr, size_t size) } retval = cur_alloc.realloc(ptr, size); end: - tracepoint(ust_libc, realloc, ptr, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(ust_libc, realloc, ptr, size, retval); + } + URCU_TLS(malloc_nesting)--; return retval; } @@ -309,6 +337,7 @@ void *memalign(size_t alignment, size_t size) { void *retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.memalign == NULL) { lookup_all_symbols(); if (cur_alloc.memalign == NULL) { @@ -317,7 +346,10 @@ void *memalign(size_t alignment, size_t size) } } retval = cur_alloc.memalign(alignment, size); - tracepoint(ust_libc, memalign, alignment, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(ust_libc, memalign, alignment, size, retval); + } + URCU_TLS(malloc_nesting)--; return retval; } @@ -325,6 +357,7 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) { int retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.posix_memalign == NULL) { lookup_all_symbols(); if (cur_alloc.posix_memalign == NULL) { @@ -333,7 +366,11 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) } } retval = cur_alloc.posix_memalign(memptr, alignment, size); - tracepoint(ust_libc, posix_memalign, *memptr, alignment, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(ust_libc, posix_memalign, *memptr, alignment, size, + retval); + } + URCU_TLS(malloc_nesting)--; return retval; } -- 2.34.1