summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--doc/safe-alloc.texi2
-rw-r--r--lib/safe-alloc.c90
-rw-r--r--lib/safe-alloc.h91
-rw-r--r--modules/safe-alloc1
5 files changed, 76 insertions, 130 deletions
diff --git a/ChangeLog b/ChangeLog
index ede9986703..2c7edd59ab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
2021-04-18 Paul Eggert <eggert@cs.ucla.edu>
+ safe-alloc: fix pointer implementation
+ The old implementation assumed that all pointers use the same
+ internal representation, but the C standard doesn’t guarantee
+ this. Use void * (pointer) not void ** (pointer-to-pointer) for
+ the internal functions’ API. The internal functions now return
+ NULL if and only if they failed, and the macros translate that
+ into -1 or 0 to satisfy the existing API.
+ * doc/safe-alloc.texi (Safe Allocation Macros): Mention overflow.
+ * lib/safe-alloc.c: Major rewrite. Now this simply
+ defines SAFE_ALLOC_INLINE and includes safe-alloc.h.
+ * lib/safe-alloc.h: Include stddef.h, not stdlib.h.
+ (SAFE_ALLOC_INLINE): New macro; use Gnulib inline function style.
+ (safe_alloc_realloc_n): New API, which passes and returns
+ the pointer, and which returns NULL if and only if failure occurs.
+ (safe_alloc_check): New function.
+ (ALLOC, ALLOC_N, ALLOC_N_UNINITIALIZED, REALLOC_N):
+ Redo using the new API for internal functions, and using calloc
+ which is good enough since it’s GNU-compatible now.
+ (FREE): Expand to an expression rather than merely to something
+ that needs a following ‘;’ to become a statement.
+ * modules/safe-alloc (Depends-on): Add calloc-gnu.
+
calloc-gnu: now LGPLv2+
* modules/calloc-gnu (License): Change from GPL to LGPLv2+.
The old value was evidently a longstanding typo, and calloc
diff --git a/doc/safe-alloc.texi b/doc/safe-alloc.texi
index d40ec65b63..e896e25982 100644
--- a/doc/safe-alloc.texi
+++ b/doc/safe-alloc.texi
@@ -13,6 +13,8 @@ Some of the memory allocation mistakes that are commonly made are
passing the incorrect number of bytes to @code{malloc}, especially
when allocating an array,
@item
+unchecked integer overflow when calculating array sizes,
+@item
fail to check the return value of @code{malloc} and @code{realloc} for
errors,
@item
diff --git a/lib/safe-alloc.c b/lib/safe-alloc.c
index 116ac4371c..df061f9efb 100644
--- a/lib/safe-alloc.c
+++ b/lib/safe-alloc.c
@@ -1,91 +1,3 @@
-/* safe-alloc.c: safer memory allocation
-
- Copyright (C) 2009-2021 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 3 of the License, or any
- later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
-
-/* Written by Daniel Berrange <berrange@redhat.com>, 2008 */
-
#include <config.h>
-
-/* Specification. */
+#define SAFE_ALLOC_INLINE _GL_EXTERN_INLINE
#include "safe-alloc.h"
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <errno.h>
-
-
-/**
- * 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 (zeroed)
- *(void **) ptrptr = calloc (count, size);
- else
- *(void **) ptrptr = reallocarray (NULL, 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;
- }
- tmp = reallocarray (*(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
index 1c655734ec..7de424f3c6 100644
--- a/lib/safe-alloc.h
+++ b/lib/safe-alloc.h
@@ -15,76 +15,89 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
-/* Written by Daniel Berrange <berrange@redhat.com>, 2008 */
+/* Written by Daniel Berrange and Paul Eggert. */
#ifndef SAFE_ALLOC_H_
-# define SAFE_ALLOC_H_
+#define SAFE_ALLOC_H_
-# include <stdlib.h>
+#include <stdlib.h>
-/* Don't call these directly - use the macros below */
-int
-safe_alloc_alloc_n (void *ptrptr, size_t size, size_t count, int zeroed)
- _GL_ATTRIBUTE_NODISCARD;
+#ifndef _GL_INLINE_HEADER_BEGIN
+ #error "Please include config.h first."
+#endif
+_GL_INLINE_HEADER_BEGIN
+#ifndef SAFE_ALLOC_INLINE
+# define SAFE_ALLOC_INLINE _GL_INLINE
+#endif
-int
-safe_alloc_realloc_n (void *ptrptr, size_t size, size_t count)
- _GL_ATTRIBUTE_NODISCARD;
+/* Don't call these directly - use the macros below. */
+SAFE_ALLOC_INLINE void *
+safe_alloc_realloc_n (void *ptr, size_t count, size_t size)
+{
+ if (count == 0 || size == 0)
+ count = size = 1;
+ return reallocarray (ptr, count, size);
+}
+SAFE_ALLOC_INLINE int _GL_ATTRIBUTE_NODISCARD
+safe_alloc_check (void *ptr)
+{
+ /* Return 0 if the allocation was successful, -1 otherwise. */
+ return -!ptr;
+}
/**
* ALLOC:
- * @ptr: pointer to hold address of allocated memory
+ * @ptr: pointer to allocated memory
*
- * Allocate sizeof(*ptr) bytes of memory and store
- * the address of allocated memory in 'ptr'. Fill the
+ * 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
+ * Return -1 on failure to allocate, zero on success.
*/
-# define ALLOC(ptr) \
- safe_alloc_alloc_n (&(ptr), sizeof (*(ptr)), 1, 1)
+#define ALLOC(ptr) ALLOC_N (ptr, 1)
/**
* ALLOC_N:
- * @ptr: pointer to hold address of allocated memory
+ * @ptr: pointer to allocated memory
* @count: number of elements to allocate
*
- * Allocate an array of 'count' elements, each sizeof(*ptr)
+ * 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.
+ * 'ptr'. Fill the newly allocated memory with zeros.
*
- * Return -1 on failure, 0 on success
+ * Return -1 on failure, 0 on success.
*/
-# define ALLOC_N(ptr, count) \
- safe_alloc_alloc_n (&(ptr), sizeof (*(ptr)), (count), 1)
+#define ALLOC_N(ptr, count) \
+ safe_alloc_check ((ptr) = calloc (count, sizeof *(ptr)))
/**
* ALLOC_N_UNINITIALIZED:
- * @ptr: pointer to hold address of allocated memory
+ * @ptr: pointer to allocated memory
* @count: number of elements to allocate
*
- * Allocate an array of 'count' elements, each sizeof(*ptr)
+ * 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.
+ * 'ptr'. Do not initialize the new memory at all.
*
- * Return -1 on failure to allocate, zero on success
+ * Return -1 on failure to allocate, zero on success.
*/
-# define ALLOC_N_UNINITIALIZED(ptr, count) \
- safe_alloc_alloc_n (&(ptr), sizeof (*(ptr)), (count), 0)
+#define ALLOC_N_UNINITIALIZED(ptr, count) \
+ safe_alloc_check ((ptr) = safe_alloc_realloc_n (NULL, count, sizeof *(ptr)))
/**
* REALLOC_N:
- * @ptr: pointer to hold address of allocated memory
+ * @ptr: pointer to allocated memory
* @count: number of elements to allocate
*
- * Re-allocate an array of 'count' elements, each sizeof(*ptr)
+ * 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
+ * 'ptr'. Fill the newly allocated memory with zeros.
*
- * Return -1 on failure to reallocate, zero on success
+ * Return -1 on failure to reallocate, zero on success.
*/
-# define REALLOC_N(ptr, count) \
- safe_alloc_realloc_n (&(ptr), sizeof (*(ptr)), (count))
+#define REALLOC_N(ptr, count) \
+ safe_alloc_check ((ptr) = safe_alloc_realloc_n (ptr, count, sizeof *(ptr)))
/**
* FREE:
@@ -93,12 +106,8 @@ safe_alloc_realloc_n (void *ptrptr, size_t size, size_t count)
* Free the memory stored in 'ptr' and update to point
* to NULL.
*/
-# define FREE(ptr) \
- do \
- { \
- free (ptr); \
- (ptr) = NULL; \
- } \
- while (0)
+#define FREE(ptr) ((void) (free (ptr), (ptr) = NULL))
+
+_GL_INLINE_HEADER_END
#endif /* SAFE_ALLOC_H_ */
diff --git a/modules/safe-alloc b/modules/safe-alloc
index 9453b49ee5..180aa8a2de 100644
--- a/modules/safe-alloc
+++ b/modules/safe-alloc
@@ -7,6 +7,7 @@ lib/safe-alloc.c
m4/safe-alloc.m4
Depends-on:
+calloc-gnu
reallocarray
configure.ac: