Add wrappers for commonly used memory allocation functions. These wrappers
authorRussell Bryant <russell@russellbryant.com>
Tue, 10 Jan 2006 23:51:42 +0000 (23:51 +0000)
committerRussell Bryant <russell@russellbryant.com>
Tue, 10 Jan 2006 23:51:42 +0000 (23:51 +0000)
add an automatically generated Asterisk log message if the allocation fails
for some reason.  Otherwise, they are functionally the same, with the
exception of ast_strdup and ast_strndup.  These functions have the added
ability to accept a NULL argument without error, which will just be ignored
without generating an error. The coding guidelines have also been updated to
reflect all of this information.  (issue #4996)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7952 65c4cc65-6c06-0410-ace0-fbb531ad65f3

doc/CODING-GUIDELINES
include/asterisk/utils.h

index 3d296a7..42d54ac 100644 (file)
@@ -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
 --------------
index 8fd4244..ed842e1 100644 (file)
@@ -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 */