core: Stop using AST_INLINE_API for allocator functions.

This replaces AST_INLINE_API allocators in utils.h with real functions
implemented in astmm.c.  Associated macro's are also moved from utils.h
to astmm.h.

Remove menuselect conflicts between MALLOC_DEBUG and DEBUG_CHAOS as they
can now be combined.

This has multiple benefits:
* Simplifies asterisk/utils.h by removing inline functions and use of
  the logger.
* Removal of these inline functions decreases size of Asterisk and
  module binaries by 1% or more.
* Puts memory management functions together with and without
  MALLOC_DEBUG enabled, simplifying management of the code.
* Enables DEBUG_CHAOS for ASTMM_REDIRECT and bundled pjproject.

Change-Id: If9df4377f74bdbb627461b27a473123e05525887
This commit is contained in:
Corey Farrell
2018-03-14 05:27:40 -04:00
parent d5bfba60d2
commit 4d1c9d8711
13 changed files with 409 additions and 667 deletions

View File

@@ -483,364 +483,6 @@ long int ast_random(void);
*/
#define ast_random_double() (((double)ast_random()) / RAND_MAX)
/*!
* \brief DEBUG_CHAOS returns failure randomly
*
* DEBUG_CHAOS_RETURN(failure); can be used to fake
* failure of functions such as memory allocation,
* for the purposes of testing failure handling.
*/
#ifdef DEBUG_CHAOS
#ifndef DEBUG_CHAOS_ALLOC_CHANCE
#define DEBUG_CHAOS_ALLOC_CHANCE 100000
#endif
/* Could #define DEBUG_CHAOS_ENABLE ast_fully_booted */
#ifndef DEBUG_CHAOS_ENABLE
#define DEBUG_CHAOS_ENABLE 1
#endif
#define DEBUG_CHAOS_RETURN(CHANCE, FAILURE) \
do { \
if ((DEBUG_CHAOS_ENABLE) && (ast_random() % CHANCE == 0)) { \
return FAILURE; \
} \
} while (0)
#else
#define DEBUG_CHAOS_RETURN(c,f)
#endif
#if !defined(NO_MALLOC_DEBUG) && !defined(STANDALONE) && !defined(STANDALONE2)
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);
/*!
* \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.
*/
void ast_free_ptr(void *ptr);
void __ast_free(void *ptr, const char *file, int lineno, const char *func);
#else
/*
* Need to defeat the MALLOC_DEBUG API when building the standalone utilities.
*/
#define ast_std_malloc malloc
#define ast_std_calloc calloc
#define ast_std_realloc realloc
#define ast_std_free free
#define ast_free_ptr free
#define ast_free free
#define __ast_repl_calloc(nmemb, size, file, lineno, func) \
calloc(nmemb, size)
#define __ast_repl_calloc_cache(nmemb, size, file, lineno, func) \
calloc(nmemb, size)
#define __ast_repl_malloc(size, file, lineno, func) \
malloc(size)
#define __ast_repl_realloc(ptr, size, file, lineno, func) \
realloc(ptr, size)
#define __ast_repl_strdup(s, file, lineno, func) \
strdup(s)
#define __ast_repl_strndup(s, n, file, lineno, func) \
strndup(s, n)
#define __ast_repl_vasprintf(strp, format, ap, file, lineno, func) \
vasprintf(strp, format, ap)
#endif
#if defined(AST_IN_CORE)
#define MALLOC_FAILURE_MSG \
ast_log_safe(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file)
#else
#define MALLOC_FAILURE_MSG \
ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file)
#endif
AST_INLINE_API(
void * attribute_malloc __ast_malloc(size_t len, const char *file, int lineno, const char *func),
{
void *p;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
p = __ast_repl_malloc(len, file, lineno, func);
if (!p) {
MALLOC_FAILURE_MSG;
}
return p;
}
)
AST_INLINE_API(
void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
{
void *p;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
p = __ast_repl_calloc(num, len, file, lineno, func);
if (!p) {
MALLOC_FAILURE_MSG;
}
return p;
}
)
AST_INLINE_API(
void * attribute_malloc __ast_calloc_cache(size_t num, size_t len, const char *file, int lineno, const char *func),
{
void *p;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
p = __ast_repl_calloc_cache(num, len, file, lineno, func);
if (!p) {
MALLOC_FAILURE_MSG;
}
return p;
}
)
AST_INLINE_API(
void *__ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
{
void *newp;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
newp = __ast_repl_realloc(p, len, file, lineno, func);
if (!newp) {
MALLOC_FAILURE_MSG;
}
return newp;
}
)
AST_INLINE_API(
char * attribute_malloc __ast_strdup(const char *str, const char *file, int lineno, const char *func),
{
char *newstr = NULL;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
if (str) {
newstr = __ast_repl_strdup(str, file, lineno, func);
if (!newstr) {
MALLOC_FAILURE_MSG;
}
}
return newstr;
}
)
AST_INLINE_API(
char * attribute_malloc __ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
{
char *newstr = NULL;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
if (str) {
newstr = __ast_repl_strndup(str, len, file, lineno, func);
if (!newstr) {
MALLOC_FAILURE_MSG;
}
}
return newstr;
}
)
AST_INLINE_API(
__attribute__((format(printf, 5, 6)))
int __ast_asprintf(const char *file, int lineno, const char *func, char **ret, const char *fmt, ...),
{
int res;
va_list ap;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1);
va_start(ap, fmt);
res = __ast_repl_vasprintf(ret, fmt, ap, file, lineno, func);
if (res < 0) {
/*
* *ret is undefined so set to NULL to ensure it is
* initialized to something useful.
*/
*ret = NULL;
MALLOC_FAILURE_MSG;
}
va_end(ap);
return res;
}
)
AST_INLINE_API(
__attribute__((format(printf, 2, 0)))
int __ast_vasprintf(char **ret, const char *fmt, va_list ap, const char *file, int lineno, const char *func),
{
int res;
DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1);
res = __ast_repl_vasprintf(ret, fmt, ap, file, lineno, func);
if (res < 0) {
/*
* *ret is undefined so set to NULL to ensure it is
* initialized to something useful.
*/
*ret = NULL;
MALLOC_FAILURE_MSG;
}
return res;
}
)
/*!
* \brief A wrapper for malloc()
*
* ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The argument and return value are the same as malloc()
*/
#define ast_malloc(len) \
__ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief A wrapper for calloc()
*
* ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The arguments and return value are the same as calloc()
*/
#define ast_calloc(num, len) \
__ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief A wrapper for calloc() for use in cache pools
*
* ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
* message in the case that the allocation fails. When memory debugging is in use,
* the memory allocated by this function will be marked as 'cache' so it can be
* distinguished from normal memory allocations.
*
* The arguments and return value are the same as calloc()
*/
#define ast_calloc_cache(num, len) \
__ast_calloc_cache((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief A wrapper for realloc()
*
* ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The arguments and return value are the same as realloc()
*/
#define ast_realloc(p, len) \
__ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief A wrapper for strdup()
*
* ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
* argument is provided, ast_strdup will return NULL without generating any
* kind of error log message.
*
* The argument and return value are the same as strdup()
*/
#define ast_strdup(str) \
__ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief A wrapper for strndup()
*
* ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
* string to duplicate. If a NULL argument is provided, ast_strdup will return
* NULL without generating any kind of error log message.
*
* The arguments and return value are the same as strndup()
*/
#define ast_strndup(str, len) \
__ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief A wrapper for asprintf()
*
* ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The arguments and return value are the same as asprintf()
*/
#define ast_asprintf(ret, fmt, ...) \
__ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, (ret), (fmt), __VA_ARGS__)
/*!
* \brief A wrapper for vasprintf()
*
* ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The arguments and return value are the same as vasprintf()
*/
#define ast_vasprintf(ret, fmt, ap) \
__ast_vasprintf((ret), (fmt), (ap), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
\brief call __builtin_alloca to ensure we get gcc builtin semantics
\param size The size of the buffer we want allocated
This macro will attempt to allocate memory from the stack. If it fails
you won't get a NULL returned, but a SEGFAULT if you're lucky.
*/
#define ast_alloca(size) __builtin_alloca(size)
#if !defined(ast_strdupa) && defined(__GNUC__)
/*!
* \brief duplicate a string in memory from the stack
* \param s The string to duplicate
*
* This macro will duplicate the given string. It returns a pointer to the stack
* allocatted memory for the new string.
*/
#define ast_strdupa(s) \
(__extension__ \
({ \
const char *__old = (s); \
size_t __len = strlen(__old) + 1; \
char *__new = __builtin_alloca(__len); \
memcpy (__new, __old, __len); \
__new; \
}))
#endif
/*!
* \brief Disable PMTU discovery on a socket
* \param sock The socket to manipulate