+2009-02-21 David Lutterkort <lutter@redhat.com>
+
+ New module 'safe-alloc'.
+ * lib/safe-alloc.h: New file.
+ * lib/safe-alloc.c: New file.
+ * m4/safe-alloc.m4: New file.
+ * modules/safe-alloc: New file.
+ * doc/safe-alloc.texi: New file.
+ * doc/gnulib.texi: Include it.
+ * MODULES.html.sh (Memory management functions <stdlib.h>): Add
+ safe-alloc.
+
2009-02-18 Bruno Haible <bruno@clisp.org>
Fix link error on non-glibc systems.
func_module malloca
func_module xmalloca
func_module xmemdup0
+ func_module safe-alloc
func_end_table
element="Integer arithmetic functions <stdlib.h>"
* func::
* warnings::
* manywarnings::
+* Safe Allocation Macros::
@end menu
@node alloca
@include manywarnings.texi
+@include safe-alloc.texi
@node GNU Free Documentation License
@appendix GNU Free Documentation License
--- /dev/null
+@node Safe Allocation Macros
+@section Safe Allocation Macros
+
+The standard C library malloc/realloc/calloc/free APIs are prone to a
+number of common coding errors. The @code{safe-alloc} module provides
+macros that make it easier to avoid many of them. It still uses the
+standard C allocation functions behind the scenes.
+
+Some of the memory allocation mistakes that are commonly made are
+
+@itemize @bullet
+@item
+passing the incorrect number of bytes to @code{malloc}, especially
+when allocationg an array
+@item
+fail to check the return value of @code{malloc} and @code{realloc} for
+errors
+@item
+forget to fully initialize memory just allocated with @code{malloc}
+@item
+duplicate calls to @code{free} by forgetting to set the pointer
+variable to @code{NULL}
+@item
+leaking memory in calls to @code{realloc} when that call fails
+@end itemize
+
+The @code{safe-alloc} module addresses these problems in the following way:
+
+@itemize @bullet
+@item
+Define macros that wrap around the standard C allocation
+functions. That makes it possible to use the compiler's knowledge of
+the size of objects for allocation; it also allows setting pointers
+passed in as arguments when appropriate
+@item
+Use return values only for a success/fail error condition flag,
+and annotate them with GCC's @code{__warn_unused_result__}
+@item
+Use @code{calloc} in favor of @code{malloc}
+@end itemize
+
+@defmac {int} ALLOC (ptr)
+@findex ALLOC
+Allocate @code{sizeof(*ptr)} bytes of memory and store the address of
+allocated memory in @code{ptr}. Fill the newly allocated memory with
+zeros.
+
+Returns -1 on failure, 0 on success.
+@end defmac
+
+@defmac {int} ALLOC_N(ptr, count)
+@findex ALLOC_N
+Allocate an array of @code{count} elements, each @code{sizeof(*ptr)}
+bytes long and store the address of allocated memory in
+@code{ptr}. Fill the newly allocated memory with zeros.
+
+Returns -1 on failure, 0 on success.
+@end defmac
+
+@defmac {int} ALLOC_N_UNINITIALIZED(ptr, count)
+@findex ALLOC_N_UNINITIALIZED
+Allocate an array of @code{count} elements, each @code{sizeof(*ptr)}
+bytes long and store the address of allocated memory in
+@code{ptr}. The allocated memory is not initialized.
+
+Returns -1 on failure, 0 on success.
+@end defmac
+
+@defmac {int} REALLOC_N(ptr, count)
+@findex REALLOC_N
+Reallocate the memory pointedto by @code{ptr} to be big enough to hold
+at least @code{count} elements, each @code{sizeof(*ptr)} bytes long
+and store the address of allocated memory in @code{ptr}. If
+reallocation fails, the @code{ptr} is not modified.
+
+Returns -1 on failure, 0 on success.
+@end defmac
+
+@defmac {void} FREE(ptr)
+@findex FREE
+Free the memory stored in @code{ptr} and set @code{ptr} to
+@code{NULL}.
+@end defmac
--- /dev/null
+/*
+ * safe-alloc.c: safer memory allocation
+ *
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Written by Daniel Berrange <berrange@redhat.com>, 2008 */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "safe-alloc.h"
+
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+ to size arithmetic overflow. S must be positive and N must be
+ nonnegative. This is a macro, not an inline function, so that it
+ works correctly even when SIZE_MAX < N.
+
+ By gnulib convention, SIZE_MAX represents overflow in size
+ calculations, so the conservative dividend to use here is
+ SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+ However, malloc (SIZE_MAX) fails on all known hosts where
+ sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+ exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+ branch when S is known to be 1.
+
+ This is the same as xalloc_oversized from xalloc.h
+*/
+#define safe_alloc_oversized(n, s) \
+ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+
+
+/**
+ * safe_alloc_alloc_n:
+ * @ptrptr: pointer to pointer for address of allocated memory
+ * @size: number of bytes to allocate
+ * @count: number of elements to allocate
+ *
+ * Allocate an array of memory 'count' elements long,
+ * each with 'size' bytes. Return the address of the
+ * allocated memory in 'ptrptr'. The newly allocated
+ * memory is filled with zeros.
+ *
+ * Return -1 on failure to allocate, zero on success
+ */
+int
+safe_alloc_alloc_n (void *ptrptr, size_t size, size_t count, int zeroed)
+{
+ if (size == 0 || count == 0)
+ {
+ *(void **) ptrptr = NULL;
+ return 0;
+ }
+
+ if (safe_alloc_oversized (count, size))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (zeroed)
+ *(void **) ptrptr = calloc (count, size);
+ else
+ *(void **) ptrptr = malloc (count * size);
+
+ if (*(void **) ptrptr == NULL)
+ return -1;
+ return 0;
+}
+
+/**
+ * safe_alloc_realloc_n:
+ * @ptrptr: pointer to pointer for address of allocated memory
+ * @size: number of bytes to allocate
+ * @count: number of elements in array
+ *
+ * Resize the block of memory in 'ptrptr' to be an array of
+ * 'count' elements, each 'size' bytes in length. Update 'ptrptr'
+ * with the address of the newly allocated memory. On failure,
+ * 'ptrptr' is not changed and still points to the original memory
+ * block. The newly allocated memory is filled with zeros.
+ *
+ * Return -1 on failure to allocate, zero on success
+ */
+int
+safe_alloc_realloc_n (void *ptrptr, size_t size, size_t count)
+{
+ void *tmp;
+ if (size == 0 || count == 0)
+ {
+ free (*(void **) ptrptr);
+ *(void **) ptrptr = NULL;
+ return 0;
+ }
+ if (safe_alloc_oversized (count, size))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ tmp = realloc (*(void **) ptrptr, size * count);
+ if (!tmp)
+ return -1;
+ *(void **) ptrptr = tmp;
+ return 0;
+}
--- /dev/null
+/*
+ * memory.c: safer memory allocation
+ *
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Written by Daniel Berrange <berrange@redhat.com>, 2008 */
+
+#ifndef SAFE_ALLOC_H_
+# define SAFE_ALLOC_H_
+
+# include <stdlib.h>
+
+# ifndef ATTRIBUTE_RETURN_CHECK
+# if __GNUC_PREREQ (3, 4)
+# define ATTRIBUTE_RETURN_CHECK __attribute__((__warn_unused_result__))
+# else
+# define ATTRIBUTE_RETURN_CHECK
+# endif
+# endif
+
+/* Don't call these directly - use the macros below */
+int
+safe_alloc_alloc_n (void *ptrptr, size_t size, size_t count, int zeroed)
+ ATTRIBUTE_RETURN_CHECK;
+
+int
+safe_alloc_realloc_n (void *ptrptr, size_t size, size_t count)
+ ATTRIBUTE_RETURN_CHECK;
+
+/**
+ * ALLOC:
+ * @ptr: pointer to hold address of allocated memory
+ *
+ * Allocate sizeof(*ptr) bytes of memory and store
+ * the address of allocated memory in 'ptr'. Fill the
+ * newly allocated memory with zeros.
+ *
+ * Return -1 on failure to allocate, zero on success
+ */
+# define ALLOC(ptr) \
+ safe_alloc_alloc_n (&(ptr), sizeof(*(ptr)), 1, 1)
+
+/**
+ * ALLOC_N:
+ * @ptr: pointer to hold address of allocated memory
+ * @count: number of elements to allocate
+ *
+ * Allocate an array of 'count' elements, each sizeof(*ptr)
+ * bytes long and store the address of allocated memory in
+ * 'ptr'. Fill the newly allocated memory with zeros.
+ *
+ * Return -1 on failure, 0 on success
+ */
+# define ALLOC_N(ptr, count) \
+ safe_alloc_alloc_n (&(ptr), sizeof(*(ptr)), (count), 1)
+
+/**
+ * ALLOC_N_UNINITIALIZED:
+ * @ptr: pointer to hold address of allocated memory
+ * @count: number of elements to allocate
+ *
+ * Allocate an array of 'count' elements, each sizeof(*ptr)
+ * bytes long and store the address of allocated memory in
+ * 'ptr'. Do not initialize the new memory at all.
+ *
+ * Return -1 on failure to allocate, zero on success
+ */
+# define ALLOC_N_UNINITIALIZED(ptr, count) \
+ safe_alloc_alloc_n (&(ptr), sizeof(*(ptr)), (count), 0)
+
+/**
+ * REALLOC_N:
+ * @ptr: pointer to hold address of allocated memory
+ * @count: number of elements to allocate
+ *
+ * Re-allocate an array of 'count' elements, each sizeof(*ptr)
+ * bytes long and store the address of allocated memory in
+ * 'ptr'. Fill the newly allocated memory with zeros
+ *
+ * Return -1 on failure to reallocate, zero on success
+ */
+# define REALLOC_N(ptr, count) \
+ safe_alloc_realloc_n (&(ptr), sizeof(*(ptr)), (count))
+
+/**
+ * FREE:
+ * @ptr: pointer holding address to be freed
+ *
+ * Free the memory stored in 'ptr' and update to point
+ * to NULL.
+ */
+# define FREE(ptr) \
+ do \
+ { \
+ free(ptr); \
+ (ptr) = NULL; \
+ } \
+ while(0)
+
+#endif /* SAFE_ALLOC_H_ */
--- /dev/null
+# safe-alloc.m4 serial 1
+dnl Copyright (C) 2009 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+AC_DEFUN([gl_SAFE_ALLOC],
+[
+ AC_LIBOBJ([safe-alloc])
+])
--- /dev/null
+Description:
+A set of macros to make calls to alloc/calloc/realloc safer.
+
+Files:
+lib/safe-alloc.h
+lib/safe-alloc.c
+m4/safe-alloc.m4
+
+configure.ac:
+gl_SAFE_ALLOC
+
+Makefile.am:
+
+Include:
+"safe-alloc.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+David Lutterkort