From: David Lutterkort Date: Sat, 21 Feb 2009 10:08:37 +0000 (+0100) Subject: New module 'safe-alloc'. X-Git-Tag: v0.1~6313 X-Git-Url: http://erislabs.org.uk/gitweb/?a=commitdiff_plain;h=032310a69161066be953842f2dc69efae2f745a1;p=gnulib.git New module 'safe-alloc'. --- diff --git a/ChangeLog b/ChangeLog index d54e782e1..da030f0ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2009-02-21 David Lutterkort + + 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 ): Add + safe-alloc. + 2009-02-18 Bruno Haible Fix link error on non-glibc systems. diff --git a/MODULES.html.sh b/MODULES.html.sh index 0154242bd..614523476 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -1724,6 +1724,7 @@ func_all_modules () func_module malloca func_module xmalloca func_module xmemdup0 + func_module safe-alloc func_end_table element="Integer arithmetic functions " diff --git a/doc/gnulib.texi b/doc/gnulib.texi index d9383f6a9..fc623b5ad 100644 --- a/doc/gnulib.texi +++ b/doc/gnulib.texi @@ -5824,6 +5824,7 @@ This list of functions is sorted according to the header that declares them. * func:: * warnings:: * manywarnings:: +* Safe Allocation Macros:: @end menu @node alloca @@ -5914,6 +5915,7 @@ generated automatically. @include manywarnings.texi +@include safe-alloc.texi @node GNU Free Documentation License @appendix GNU Free Documentation License diff --git a/doc/safe-alloc.texi b/doc/safe-alloc.texi new file mode 100644 index 000000000..bd398907e --- /dev/null +++ b/doc/safe-alloc.texi @@ -0,0 +1,83 @@ +@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 diff --git a/lib/safe-alloc.c b/lib/safe-alloc.c new file mode 100644 index 000000000..fca8754c8 --- /dev/null +++ b/lib/safe-alloc.c @@ -0,0 +1,124 @@ +/* + * 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 , 2008 */ + +#include + +#include +#include +#include + +#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; +} diff --git a/lib/safe-alloc.h b/lib/safe-alloc.h new file mode 100644 index 000000000..1b7847add --- /dev/null +++ b/lib/safe-alloc.h @@ -0,0 +1,116 @@ +/* + * 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 , 2008 */ + +#ifndef SAFE_ALLOC_H_ +# define SAFE_ALLOC_H_ + +# include + +# 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_ */ diff --git a/m4/safe-alloc.m4 b/m4/safe-alloc.m4 new file mode 100644 index 000000000..c8fff08a2 --- /dev/null +++ b/m4/safe-alloc.m4 @@ -0,0 +1,9 @@ +# 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]) +]) diff --git a/modules/safe-alloc b/modules/safe-alloc new file mode 100644 index 000000000..bffbecc47 --- /dev/null +++ b/modules/safe-alloc @@ -0,0 +1,21 @@ +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