diff --git a/dbg_mlc.c b/dbg_mlc.c index 2987699f0..4da3b4cd2 100644 --- a/dbg_mlc.c +++ b/dbg_mlc.c @@ -558,7 +558,7 @@ GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb, return(0); } result = GC_store_debug_info_inner(base, (word)lb, "INTERNAL", 0); - ADD_CALL_CHAIN(base, GC_RETURN_ADDR); + ADD_CALL_CHAIN_INNER(base); return result; } #endif /* DBG_HDRS_ALL */ diff --git a/include/private/dbg_mlc.h b/include/private/dbg_mlc.h index 8e08a1a9b..9ecb78f1c 100644 --- a/include/private/dbg_mlc.h +++ b/include/private/dbg_mlc.h @@ -129,6 +129,12 @@ typedef struct { GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]); GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]); # define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci) +# if defined(REDIRECT_MALLOC) && defined(THREADS) && defined(DBG_HDRS_ALL) \ + && NARGS == 0 && NFRAMES % 2 == 0 && defined(GC_HAVE_BUILTIN_BACKTRACE) + GC_INNER void GC_save_callers_no_unlock(struct callinfo info[NFRAMES]); +# define ADD_CALL_CHAIN_INNER(base) \ + GC_save_callers_no_unlock(((oh *)(base)) -> oh_ci) +# endif # define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) #elif defined(GC_ADD_CALLER) struct callinfo; @@ -140,6 +146,11 @@ typedef struct { # define PRINT_CALL_CHAIN(base) #endif +#if !defined(ADD_CALL_CHAIN_INNER) && defined(DBG_HDRS_ALL) + /* A variant of ADD_CALL_CHAIN() used for internal allocations. */ +# define ADD_CALL_CHAIN_INNER(base) ADD_CALL_CHAIN(base, GC_RETURN_ADDR) +#endif + #ifdef GC_ADD_CALLER # define OPT_RA ra, #else diff --git a/os_dep.c b/os_dep.c index c0e72ba56..2e9e9c0fb 100644 --- a/os_dep.c +++ b/os_dep.c @@ -4561,13 +4561,32 @@ GC_API int GC_CALL GC_get_pages_executable(void) /* you could use something like pthread_getspecific. */ # endif GC_in_save_callers = FALSE; -#endif + +# if defined(THREADS) && defined(DBG_HDRS_ALL) +# include "private/dbg_mlc.h" + + /* A dummy version of GC_save_callers() which does not call */ + /* backtrace(). */ + GC_INNER void GC_save_callers_no_unlock(struct callinfo info[NFRAMES]) + { + GC_ASSERT(I_HOLD_LOCK()); + info[0].ci_pc = (word)(&GC_save_callers_no_unlock); + BZERO(&info[1], sizeof(void *) * (NFRAMES - 1)); + } +# endif +#endif /* REDIRECT_MALLOC */ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]) { void * tmp_info[NFRAMES + 1]; int npcs, i; + GC_ASSERT(I_HOLD_LOCK()); + /* backtrace may call dl_iterate_phdr which is also */ + /* used by GC_register_dynamic_libraries, and */ + /* dl_iterate_phdr is not guaranteed to be reentrant. */ + + GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *)); # ifdef REDIRECT_MALLOC if (GC_in_save_callers) { info[0].ci_pc = (word)(&GC_save_callers); @@ -4575,17 +4594,15 @@ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]) return; } GC_in_save_callers = TRUE; + /* backtrace() might call a redirected malloc. */ + UNLOCK(); + npcs = backtrace((void **)tmp_info, NFRAMES + 1); + LOCK(); +# else + npcs = backtrace((void **)tmp_info, NFRAMES + 1); # endif - - GC_ASSERT(I_HOLD_LOCK()); - /* backtrace may call dl_iterate_phdr which is also */ - /* used by GC_register_dynamic_libraries, and */ - /* dl_iterate_phdr is not guaranteed to be reentrant. */ - /* We retrieve NFRAMES+1 pc values, but discard the first one, since */ /* it points to our own frame. */ - GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *)); - npcs = backtrace((void **)tmp_info, NFRAMES + 1); i = 0; if (npcs > 1) { i = npcs - 1;