From 46b9e5450fbd1af030812b1933e769c86baa4932 Mon Sep 17 00:00:00 2001 From: Richard Mudgett <rmudgett@digium.com> Date: Fri, 23 Aug 2013 18:07:40 +0000 Subject: [PATCH] Fix memory corruption when trying to get "core show locks". Review https://reviewboard.asterisk.org/r/2580/ tried to fix the mismatch in memory pools but had a math error determining the buffer size and didn't address other similar memory pool mismatches. * Effectively reverted the previous patch to go in the same direction as trunk for the returned memory pool of ast_bt_get_symbols(). * Fixed memory leak in ast_bt_get_symbols() when BETTER_BACKTRACES is defined. * Fixed some formatting in ast_bt_get_symbols(). * Fixed sig_pri.c freeing memory allocated by libpri when MALLOC_DEBUG is enabled. * Fixed __dump_backtrace() freeing memory from ast_bt_get_symbols() when MALLOC_DEBUG is enabled. * Moved __dump_backtrace() because of compile issues with the utils directory. (closes issue ASTERISK-22221) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2778/ ........ Merged revisions 397525 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 397528 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397570 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/sig_pri.c | 2 +- include/asterisk/astmm.h | 6 ++++ include/asterisk/backtrace.h | 2 +- include/asterisk/lock.h | 16 --------- include/asterisk/utils.h | 16 ++++----- main/astmm.c | 32 ++++++++++++++--- main/astobj2.c | 2 +- main/backtrace.c | 67 +++++++++++++++++++----------------- main/lock.c | 17 +++++++++ main/logger.c | 4 +-- main/utils.c | 5 ++- 11 files changed, 97 insertions(+), 72 deletions(-) diff --git a/channels/sig_pri.c b/channels/sig_pri.c index 8a63600bf9..b6a04b67fa 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -9430,7 +9430,7 @@ void sig_pri_cli_show_span(int fd, int *dchannels, struct sig_pri_span *pri) info_str = pri_dump_info_str(pri->pri); if (info_str) { ast_cli(fd, "%s", info_str); - free(info_str); + ast_std_free(info_str); } #else pri_dump_info(pri->pri); diff --git a/include/asterisk/astmm.h b/include/asterisk/astmm.h index c2a717550e..1b008120a7 100644 --- a/include/asterisk/astmm.h +++ b/include/asterisk/astmm.h @@ -54,6 +54,12 @@ extern "C" { #undef vasprintf #undef free +void *ast_std_malloc(size_t size); +void *ast_std_calloc(size_t nmemb, size_t size); +void *ast_std_realloc(void *ptr, size_t size); +void ast_std_free(void *ptr); +void ast_free_ptr(void *ptr); + void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func); void *__ast_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func); void *__ast_malloc(size_t size, const char *file, int lineno, const char *func); diff --git a/include/asterisk/backtrace.h b/include/asterisk/backtrace.h index fef1d86faa..95358bfd26 100644 --- a/include/asterisk/backtrace.h +++ b/include/asterisk/backtrace.h @@ -87,7 +87,7 @@ void *__ast_bt_destroy(struct ast_bt *bt); * \param addresses A list of addresses, such as the ->addresses structure element of struct ast_bt. * \param num_frames Number of addresses in the addresses list * \retval NULL Unable to allocate memory - * \return List of strings. This should be freed with a single call to free. + * \return List of strings. Free the entire list with a single ast_std_free call. * \since 1.6.2.16 */ char **__ast_bt_get_symbols(void **addresses, size_t num_frames); diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index 34e9444766..aee084f322 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -290,22 +290,6 @@ void ast_remove_lock_info(void *lock_addr); #endif /* HAVE_BKTR */ #endif /* !defined(LOW_MEMORY) */ -#ifdef HAVE_BKTR -static inline void __dump_backtrace(struct ast_bt *bt, int canlog) -{ - char **strings; - - ssize_t i; - - strings = backtrace_symbols(bt->addresses, bt->num_frames); - - for (i = 0; i < bt->num_frames; i++) - __ast_mutex_logger("%s\n", strings[i]); - - free(strings); -} -#endif - /*! * \brief log info for the current lock with ast_log(). * diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 1623775b92..e24dc02d89 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -465,24 +465,20 @@ long int ast_random(void); */ #define ast_random_double() (((double)ast_random()) / RAND_MAX) +#ifndef __AST_DEBUG_MALLOC +#define ast_std_malloc malloc +#define ast_std_calloc calloc +#define ast_std_realloc realloc +#define ast_std_free free + /*! * \brief free() wrapper * * ast_free_ptr should be used when a function pointer for free() needs to be passed * as the argument to a function. Otherwise, astmm will cause seg faults. */ -#ifdef __AST_DEBUG_MALLOC -static void ast_free_ptr(void *ptr) attribute_unused; -static void ast_free_ptr(void *ptr) -{ - ast_free(ptr); -} -#else #define ast_free free #define ast_free_ptr ast_free -#endif - -#ifndef __AST_DEBUG_MALLOC /* * This buffer is in static memory. We never intend to read it, diff --git a/main/astmm.c b/main/astmm.c index d01b745b05..2e1016ab5d 100644 --- a/main/astmm.c +++ b/main/astmm.c @@ -158,6 +158,31 @@ AST_MUTEX_DEFINE_STATIC_NOTRACKING(reglock); } \ } while (0) +void *ast_std_malloc(size_t size) +{ + return malloc(size); +} + +void *ast_std_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + +void *ast_std_realloc(void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +void ast_std_free(void *ptr) +{ + free(ptr); +} + +void ast_free_ptr(void *ptr) +{ + ast_free(ptr); +} + static void print_backtrace(struct ast_bt *bt) { int i = 0; @@ -172,11 +197,10 @@ static void print_backtrace(struct ast_bt *bt) for (i = 3; i < bt->num_frames - 2; i++) { astmm_log("#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]); } - free(strings); + ast_std_free(strings); } } - /*! * \internal * @@ -343,9 +367,7 @@ static void region_free(struct ast_freed_regions *freed, struct ast_region *reg) if (old) { region_data_check(old); - if (old->bt) { - old->bt = ast_bt_destroy(old->bt); - } + old->bt = ast_bt_destroy(old->bt); free(old); } } diff --git a/main/astobj2.c b/main/astobj2.c index bbe77859d1..cc6ab7348f 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -132,7 +132,7 @@ void ao2_bt(void) for(i = 0; i < c; i++) { ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]); } - free(strings); + ast_std_free(strings); } #endif diff --git a/main/backtrace.c b/main/backtrace.c index 001699d001..a1156467f7 100644 --- a/main/backtrace.c +++ b/main/backtrace.c @@ -40,17 +40,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); #include <bfd.h> #endif -/* Undefine the overrides for memory allocation. astmm.c uses these functions - * as well. - */ -#undef calloc -#undef malloc -#undef free -#undef realloc - struct ast_bt *__ast_bt_create(void) { - struct ast_bt *bt = calloc(1, sizeof(*bt)); + struct ast_bt *bt = ast_std_calloc(1, sizeof(*bt)); + if (!bt) { return NULL; } @@ -69,15 +62,15 @@ int __ast_bt_get_addresses(struct ast_bt *bt) void *__ast_bt_destroy(struct ast_bt *bt) { - if (bt->alloced) { - free(bt); + if (bt && bt->alloced) { + ast_std_free(bt); } return NULL; } char **__ast_bt_get_symbols(void **addresses, size_t num_frames) { - char **strings = NULL; + char **strings; #if defined(BETTER_BACKTRACES) int stackfr; bfd *bfdobj; /* bfd.h */ @@ -97,9 +90,12 @@ char **__ast_bt_get_symbols(void **addresses, size_t num_frames) #if defined(BETTER_BACKTRACES) strings_size = num_frames * sizeof(*strings); - eachlen = calloc(num_frames, sizeof(*eachlen)); - if (!(strings = calloc(num_frames, sizeof(*strings)))) { + eachlen = ast_std_calloc(num_frames, sizeof(*eachlen)); + strings = ast_std_calloc(num_frames, sizeof(*strings)); + if (!eachlen || !strings) { + ast_std_free(eachlen); + ast_std_free(strings); return NULL; } @@ -114,6 +110,7 @@ char **__ast_bt_get_symbols(void **addresses, size_t num_frames) if (strcmp(dli.dli_fname, "asterisk") == 0) { char asteriskpath[256]; + if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) { /* This will fail to find symbols */ dli.dli_fname = "asterisk"; @@ -121,22 +118,22 @@ char **__ast_bt_get_symbols(void **addresses, size_t num_frames) } lastslash = strrchr(dli.dli_fname, '/'); - if ( (bfdobj = bfd_openr(dli.dli_fname, NULL)) && - bfd_check_format(bfdobj, bfd_object) && - (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 && - (syms = malloc(allocsize)) && - (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) { + if ((bfdobj = bfd_openr(dli.dli_fname, NULL)) && + bfd_check_format(bfdobj, bfd_object) && + (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 && + (syms = ast_std_malloc(allocsize)) && + (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) { if (bfdobj->flags & DYNAMIC) { offset = addresses[stackfr] - dli.dli_fbase; } else { - offset = addresses[stackfr] - (void *)0; + offset = addresses[stackfr] - (void *) 0; } for (section = bfdobj->sections; section; section = section->next) { - if ( !bfd_get_section_flags(bfdobj, section) & SEC_ALLOC || - section->vma > offset || - section->size + section->vma < offset) { + if (!bfd_get_section_flags(bfdobj, section) & SEC_ALLOC || + section->vma > offset || + section->size + section->vma < offset) { continue; } @@ -151,7 +148,9 @@ char **__ast_bt_get_symbols(void **addresses, size_t num_frames) found++; if ((lastslash = strrchr(file, '/'))) { const char *prevslash; - for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--); + + for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--) { + } if (prevslash >= file) { lastslash = prevslash; } @@ -173,7 +172,7 @@ char **__ast_bt_get_symbols(void **addresses, size_t num_frames) } if (bfdobj) { bfd_close(bfdobj); - free(syms); + ast_std_free(syms); } /* Default output, if we cannot find the information within BFD */ @@ -193,27 +192,31 @@ char **__ast_bt_get_symbols(void **addresses, size_t num_frames) if (!ast_strlen_zero(msg)) { char **tmp; - eachlen[stackfr] = strlen(msg); - if (!(tmp = realloc(strings, strings_size + eachlen[stackfr] + 1))) { - free(strings); + + eachlen[stackfr] = strlen(msg) + 1; + if (!(tmp = ast_std_realloc(strings, strings_size + eachlen[stackfr]))) { + ast_std_free(strings); strings = NULL; break; /* out of stack frame iteration */ } strings = tmp; strings[stackfr] = (char *) strings + strings_size; - ast_copy_string(strings[stackfr], msg, eachlen[stackfr] + 1); - strings_size += eachlen[stackfr] + 1; + strcpy(strings[stackfr], msg);/* Safe since we just allocated the room. */ + strings_size += eachlen[stackfr]; } } if (strings) { - /* Recalculate the offset pointers */ + /* Recalculate the offset pointers because of the reallocs. */ strings[0] = (char *) strings + num_frames * sizeof(*strings); for (stackfr = 1; stackfr < num_frames; stackfr++) { - strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1] + 1; + strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1]; } } + ast_std_free(eachlen); + #else /* !defined(BETTER_BACKTRACES) */ + strings = backtrace_symbols(addresses, num_frames); #endif /* defined(BETTER_BACKTRACES) */ return strings; diff --git a/main/lock.c b/main/lock.c index 902d631193..3036e5bc4b 100644 --- a/main/lock.c +++ b/main/lock.c @@ -29,6 +29,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/utils.h" #include "asterisk/lock.h" /* Allow direct use of pthread_mutex_* / pthread_cond_* */ @@ -45,6 +46,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #undef pthread_cond_wait #undef pthread_cond_timedwait +#if defined(DEBUG_THREADS) && defined(HAVE_BKTR) +static void __dump_backtrace(struct ast_bt *bt, int canlog) +{ + char **strings; + ssize_t i; + + strings = backtrace_symbols(bt->addresses, bt->num_frames); + + for (i = 0; i < bt->num_frames; i++) { + __ast_mutex_logger("%s\n", strings[i]); + } + + ast_std_free(strings); +} +#endif /* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */ + int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t) { diff --git a/main/logger.c b/main/logger.c index ae1537acdc..c374d2e574 100644 --- a/main/logger.c +++ b/main/logger.c @@ -1587,9 +1587,7 @@ void ast_log_backtrace(void) ast_debug(1, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]); } - /* MALLOC_DEBUG will erroneously report an error here, unless we undef the macro. */ -#undef free - free(strings); + ast_std_free(strings); } else { ast_debug(1, "Could not allocate memory for backtrace\n"); } diff --git a/main/utils.c b/main/utils.c index 1f05285560..300d057d92 100644 --- a/main/utils.c +++ b/main/utils.c @@ -862,9 +862,8 @@ static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt for (frame_iterator = 0; frame_iterator < num_frames; ++frame_iterator) { ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]); } -/* Prevent MALLOC_DEBUG from complaining */ -#undef free - free(symbols); + + ast_std_free(symbols); } else { ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n"); } -- GitLab