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 <mathieu.desnoyers@efficios.com>
#include <urcu/system.h>
#include <urcu/uatomic.h>
#include <urcu/compiler.h>
#include <urcu/system.h>
#include <urcu/uatomic.h>
#include <urcu/compiler.h>
+#include <urcu/tls-compat.h>
#include <lttng/align.h>
#define TRACEPOINT_DEFINE
#include <lttng/align.h>
#define TRACEPOINT_DEFINE
static
struct alloc_functions cur_alloc;
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.
/*
* Static allocator to use when initially executing dlsym(). It keeps a
* size_t value of each object size prior to the object.
void *retval;
retval = static_calloc_aligned(nmemb, size, 1);
void *retval;
retval = static_calloc_aligned(nmemb, size, 1);
- tracepoint(ust_libc, calloc, nmemb, size, retval);
void *retval;
retval = static_calloc_aligned(1, size, 1);
void *retval;
retval = static_calloc_aligned(1, size, 1);
- tracepoint(ust_libc, malloc, size, retval);
void static_free(void *ptr)
{
/* no-op. */
void static_free(void *ptr)
{
/* no-op. */
- tracepoint(ust_libc, free, ptr);
if (ptr)
memcpy(retval, ptr, *old_size);
end:
if (ptr)
memcpy(retval, ptr, *old_size);
end:
- tracepoint(ust_libc, realloc, ptr, size, retval);
void *retval;
retval = static_calloc_aligned(1, size, alignment);
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)
{
return retval;
}
static
int static_posix_memalign(void **memptr, size_t alignment, size_t size)
{
void *ptr;
/* Check for power of 2, larger than void *. */
if (alignment & (alignment - 1)
|| alignment < sizeof(void *)
|| alignment == 0) {
void *ptr;
/* Check for power of 2, larger than void *. */
if (alignment & (alignment - 1)
|| alignment < sizeof(void *)
|| alignment == 0) {
goto end;
}
ptr = static_calloc_aligned(1, size, alignment);
*memptr = ptr;
goto end;
}
ptr = static_calloc_aligned(1, size, alignment);
*memptr = ptr;
- if (size && !ptr)
- retval = ENOMEM;
- tracepoint(ust_libc, posix_memalign, *memptr, alignment, size, retval);
+ URCU_TLS(malloc_nesting)++;
if (cur_alloc.malloc == NULL) {
lookup_all_symbols();
if (cur_alloc.malloc == NULL) {
if (cur_alloc.malloc == NULL) {
lookup_all_symbols();
if (cur_alloc.malloc == NULL) {
}
}
retval = cur_alloc.malloc(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)
{
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)) {
/*
* 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)) {
+ goto end;
+ }
+
+ if (URCU_TLS(malloc_nesting) == 1) {
+ tracepoint(ust_libc, free, ptr);
}
if (cur_alloc.free == NULL) {
}
if (cur_alloc.free == NULL) {
+end:
+ URCU_TLS(malloc_nesting)--;
}
void *calloc(size_t nmemb, size_t size)
{
void *retval;
}
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) {
if (cur_alloc.calloc == NULL) {
lookup_all_symbols();
if (cur_alloc.calloc == NULL) {
}
}
retval = cur_alloc.calloc(nmemb, 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)--;
- /* 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.
*/
* static_calloc_align, in which case there is nothing
* to free, and we need to copy the old data.
*/
if (retval) {
memcpy(retval, ptr, *old_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;
}
retval = cur_alloc.realloc(ptr, size);
end:
}
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)--;
+ URCU_TLS(malloc_nesting)++;
if (cur_alloc.memalign == NULL) {
lookup_all_symbols();
if (cur_alloc.memalign == NULL) {
if (cur_alloc.memalign == NULL) {
lookup_all_symbols();
if (cur_alloc.memalign == NULL) {
}
}
retval = cur_alloc.memalign(alignment, 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)--;
+ URCU_TLS(malloc_nesting)++;
if (cur_alloc.posix_memalign == NULL) {
lookup_all_symbols();
if (cur_alloc.posix_memalign == NULL) {
if (cur_alloc.posix_memalign == NULL) {
lookup_all_symbols();
if (cur_alloc.posix_memalign == NULL) {
}
}
retval = cur_alloc.posix_memalign(memptr, alignment, 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)--;