diff --git a/doc/CODING-GUIDELINES b/doc/CODING-GUIDELINES index 3d296a75ce37e0bb1ac7747ae1d569b9663e8610..42d54aceb6bd5c485aebe7a1f2ccdc97d6fa8a7a 100644 --- a/doc/CODING-GUIDELINES +++ b/doc/CODING-GUIDELINES @@ -349,27 +349,43 @@ of a function you are calling; this can cause very strange stack arrangements and produce unexpected behavior. -Allocations for structures -When allocating/zeroing memory for a structure, try to use code like this: +When allocating/zeroing memory for a structure, use code like this: struct foo *tmp; ... -tmp = malloc(sizeof(*tmp)); -if (tmp) - memset(tmp, 0, sizeof(*tmp)); +tmp = ast_calloc(1, sizeof(*tmp)); -This eliminates duplication of the 'struct foo' identifier, which makes the -code easier to read and also ensures that if it is copy-and-pasted it won't -require as much editing. In fact, you can even use: +Avoid the combination of ast_malloc() and memset(). Instead, always use +ast_calloc(). This will allocate and zero the memory in a single operation. +In the case that uninitialized memory is acceptable, there should be a comment +in the code that states why this is the case. -struct foo *tmp; +Using sizeof(*tmp) instead of sizeof(struct foo) eliminates duplication of the +'struct foo' identifier, which makes the code easier to read and also ensures +that if it is copy-and-pasted it won't require as much editing. -... +The ast_* family of functions for memory allocation are functionally the same. +They just add an Asterisk log error message in the case that the allocation +fails for some reason. This eliminates the need to generate custom messages +throughout the code to log that this has occurred. + +-String Duplications + +The functions strdup and strndup can *not* accept a NULL argument. This results +in having code like this: + + if (str) + newstr = strdup(str); + else + newstr = NULL; -tmp = calloc(1, sizeof(*tmp)); +However, the ast_strdup and ast_strdup functions will happily accept a NULL +argument without generating an error. The same code can be written as: + + newstr = strdup(str); -This will allocate and zero the memory in a single operation. * CLI Commands -------------- diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 8fd42445bbad59126b08a6078c3530cc9d6f896c..ed842e1b786fe365e14522fc9337a243b919e388 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -25,6 +25,7 @@ #include "asterisk/compat.h" +#include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> /* we want to override inet_ntoa */ #include <netdb.h> @@ -33,6 +34,7 @@ #include "asterisk/lock.h" #include "asterisk/time.h" #include "asterisk/strings.h" +#include "asterisk/logger.h" /*! \note \verbatim @@ -241,4 +243,151 @@ int getloadavg(double *list, int nelem); long int ast_random(void); #endif +/*! + \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__)); \ + }) + +AST_INLINE_API( +void *_ast_malloc(size_t len, const char *file, int lineno, const char *func), +{ + void *p; + + p = malloc(len); + + if (!p) + ast_log(LOG_ERROR, "Memory Allocation Failure - '%d' bytes in function %s at line %d of %s\n", (int)len, func, lineno, file); + + return p; +} +) + +/*! + \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__)); \ + }) + +AST_INLINE_API( +void *_ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func), +{ + void *p; + + p = calloc(num, len); + + if (!p) + ast_log(LOG_ERROR, "Memory Allocation Failure - '%d' bytes in function %s at line %d of %s\n", (int)len, func, lineno, file); + + return p; +} +) + +/*! + \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__)); \ + }) + +AST_INLINE_API( +void *_ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func), +{ + void *newp; + + newp = realloc(p, len); + + if (!newp) + ast_log(LOG_ERROR, "Memory Allocation Failure - '%d' bytes in function %s at line %d of %s\n", (int)len, func, lineno, file); + + return newp; +} +) + +/*! + \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__)); \ + }) + +AST_INLINE_API( +void *_ast_strdup(const char *str, const char *file, int lineno, const char *func), +{ + char *newstr = NULL; + + if (str) { + newstr = strdup(str); + + if (!newstr) + ast_log(LOG_ERROR, "Memory Allocation Failure - Could not duplicate '%s' in function %s at line %d of %s\n", str, func, lineno, file); + } + + return newstr; +} +) + +/*! + \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__)); \ + }) + +AST_INLINE_API( +void *_ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func), +{ + char *newstr = NULL; + + if (str) { + newstr = strndup(str, len); + + if (!newstr) + ast_log(LOG_ERROR, "Memory Allocation Failure - Could not duplicate '%d' bytes of '%s' in function %s at line %d of %s\n", (int)len, str, func, lineno, file); + } + + return newstr; +} +) + #endif /* _ASTERISK_UTILS_H */