From 15fb0b2061f134f0fc3c04704375ee5d9696b20a Mon Sep 17 00:00:00 2001
From: Russell Bryant <russell@russellbryant.com>
Date: Tue, 10 Jan 2006 23:51:42 +0000
Subject: [PATCH] Add wrappers for commonly used memory allocation functions. 
 These wrappers 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    |  38 +++++++---
 include/asterisk/utils.h | 149 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 176 insertions(+), 11 deletions(-)

diff --git a/doc/CODING-GUIDELINES b/doc/CODING-GUIDELINES
index 3d296a75ce..42d54aceb6 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 8fd42445bb..ed842e1b78 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 */
-- 
GitLab