diff options
Diffstat (limited to 'gl/xalloc.h')
| -rw-r--r-- | gl/xalloc.h | 231 |
1 files changed, 91 insertions, 140 deletions
diff --git a/gl/xalloc.h b/gl/xalloc.h index da7c4b6b..f373c2fe 100644 --- a/gl/xalloc.h +++ b/gl/xalloc.h | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | /* xalloc.h -- malloc with out-of-memory checking | 1 | /* xalloc.h -- malloc with out-of-memory checking |
| 2 | 2 | ||
| 3 | Copyright (C) 1990-2000, 2003-2004, 2006-2013 Free Software Foundation, Inc. | 3 | Copyright (C) 1990-2000, 2003-2004, 2006-2023 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | This program is free software: you can redistribute it and/or modify | 5 | This program is free software: you can redistribute it and/or modify |
| 6 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
| 7 | the Free Software Foundation; either version 3 of the License, or | 7 | the Free Software Foundation, either version 3 of the License, or |
| 8 | (at your option) any later version. | 8 | (at your option) any later version. |
| 9 | 9 | ||
| 10 | This program is distributed in the hope that it will be useful, | 10 | This program is distributed in the hope that it will be useful, |
| @@ -13,57 +13,92 @@ | |||
| 13 | GNU General Public License for more details. | 13 | GNU General Public License for more details. |
| 14 | 14 | ||
| 15 | You should have received a copy of the GNU General Public License | 15 | You should have received a copy of the GNU General Public License |
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | 16 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| 17 | 17 | ||
| 18 | #ifndef XALLOC_H_ | 18 | #ifndef XALLOC_H_ |
| 19 | #define XALLOC_H_ | 19 | #define XALLOC_H_ |
| 20 | 20 | ||
| 21 | #include <stddef.h> | 21 | #include <stddef.h> |
| 22 | #include <stdlib.h> | ||
| 22 | 23 | ||
| 23 | #include "xalloc-oversized.h" | 24 | #if GNULIB_XALLOC |
| 25 | # include "idx.h" | ||
| 26 | #endif | ||
| 24 | 27 | ||
| 28 | #ifndef _GL_INLINE_HEADER_BEGIN | ||
| 29 | #error "Please include config.h first." | ||
| 30 | #endif | ||
| 25 | _GL_INLINE_HEADER_BEGIN | 31 | _GL_INLINE_HEADER_BEGIN |
| 26 | #ifndef XALLOC_INLINE | 32 | #ifndef XALLOC_INLINE |
| 27 | # define XALLOC_INLINE _GL_INLINE | 33 | # define XALLOC_INLINE _GL_INLINE |
| 28 | #endif | 34 | #endif |
| 29 | 35 | ||
| 36 | |||
| 30 | #ifdef __cplusplus | 37 | #ifdef __cplusplus |
| 31 | extern "C" { | 38 | extern "C" { |
| 32 | #endif | 39 | #endif |
| 33 | 40 | ||
| 34 | 41 | ||
| 35 | #if __GNUC__ >= 3 | 42 | #if GNULIB_XALLOC_DIE |
| 36 | # define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) | ||
| 37 | #else | ||
| 38 | # define _GL_ATTRIBUTE_MALLOC | ||
| 39 | #endif | ||
| 40 | |||
| 41 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) | ||
| 42 | # define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args)) | ||
| 43 | #else | ||
| 44 | # define _GL_ATTRIBUTE_ALLOC_SIZE(args) | ||
| 45 | #endif | ||
| 46 | 43 | ||
| 47 | /* This function is always triggered when memory is exhausted. | 44 | /* This function is always triggered when memory is exhausted. |
| 48 | It must be defined by the application, either explicitly | 45 | It must be defined by the application, either explicitly |
| 49 | or by using gnulib's xalloc-die module. This is the | 46 | or by using gnulib's xalloc-die module. This is the |
| 50 | function to call when one wants the program to die because of a | 47 | function to call when one wants the program to die because of a |
| 51 | memory allocation failure. */ | 48 | memory allocation failure. */ |
| 52 | extern _Noreturn void xalloc_die (void); | 49 | /*extern*/ _Noreturn void xalloc_die (void); |
| 50 | |||
| 51 | #endif /* GNULIB_XALLOC_DIE */ | ||
| 52 | |||
| 53 | #if GNULIB_XALLOC | ||
| 53 | 54 | ||
| 54 | void *xmalloc (size_t s) | 55 | void *xmalloc (size_t s) |
| 55 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1)); | 56 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE |
| 57 | _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 58 | void *ximalloc (idx_t s) | ||
| 59 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE | ||
| 60 | _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 61 | void *xinmalloc (idx_t n, idx_t s) | ||
| 62 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE | ||
| 63 | _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 56 | void *xzalloc (size_t s) | 64 | void *xzalloc (size_t s) |
| 57 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1)); | 65 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE |
| 66 | _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 67 | void *xizalloc (idx_t s) | ||
| 68 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE | ||
| 69 | _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 58 | void *xcalloc (size_t n, size_t s) | 70 | void *xcalloc (size_t n, size_t s) |
| 59 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)); | 71 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE |
| 72 | _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 73 | void *xicalloc (idx_t n, idx_t s) | ||
| 74 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE | ||
| 75 | _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 60 | void *xrealloc (void *p, size_t s) | 76 | void *xrealloc (void *p, size_t s) |
| 61 | _GL_ATTRIBUTE_ALLOC_SIZE ((2)); | 77 | _GL_ATTRIBUTE_ALLOC_SIZE ((2)); |
| 62 | void *x2realloc (void *p, size_t *pn); | 78 | void *xirealloc (void *p, idx_t s) |
| 79 | _GL_ATTRIBUTE_ALLOC_SIZE ((2)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 80 | void *xreallocarray (void *p, size_t n, size_t s) | ||
| 81 | _GL_ATTRIBUTE_ALLOC_SIZE ((2, 3)); | ||
| 82 | void *xireallocarray (void *p, idx_t n, idx_t s) | ||
| 83 | _GL_ATTRIBUTE_ALLOC_SIZE ((2, 3)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 84 | void *x2realloc (void *p, size_t *ps) /* superseded by xpalloc */ | ||
| 85 | _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 86 | void *x2nrealloc (void *p, size_t *pn, size_t s) /* superseded by xpalloc */ | ||
| 87 | _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 88 | void *xpalloc (void *pa, idx_t *pn, idx_t n_incr_min, ptrdiff_t n_max, idx_t s) | ||
| 89 | _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 63 | void *xmemdup (void const *p, size_t s) | 90 | void *xmemdup (void const *p, size_t s) |
| 64 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((2)); | 91 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE |
| 92 | _GL_ATTRIBUTE_ALLOC_SIZE ((2)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 93 | void *ximemdup (void const *p, idx_t s) | ||
| 94 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE | ||
| 95 | _GL_ATTRIBUTE_ALLOC_SIZE ((2)) _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 96 | char *ximemdup0 (void const *p, idx_t s) | ||
| 97 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE | ||
| 98 | _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 65 | char *xstrdup (char const *str) | 99 | char *xstrdup (char const *str) |
| 66 | _GL_ATTRIBUTE_MALLOC; | 100 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE |
| 101 | _GL_ATTRIBUTE_RETURNS_NONNULL; | ||
| 67 | 102 | ||
| 68 | /* In the following macros, T must be an elementary or structure/union or | 103 | /* In the following macros, T must be an elementary or structure/union or |
| 69 | typedef'ed type, or a pointer to such a type. To apply one of the | 104 | typedef'ed type, or a pointer to such a type. To apply one of the |
| @@ -72,153 +107,60 @@ char *xstrdup (char const *str) | |||
| 72 | 107 | ||
| 73 | /* Allocate an object of type T dynamically, with error checking. */ | 108 | /* Allocate an object of type T dynamically, with error checking. */ |
| 74 | /* extern t *XMALLOC (typename t); */ | 109 | /* extern t *XMALLOC (typename t); */ |
| 75 | #define XMALLOC(t) ((t *) xmalloc (sizeof (t))) | 110 | # define XMALLOC(t) ((t *) xmalloc (sizeof (t))) |
| 76 | 111 | ||
| 77 | /* Allocate memory for N elements of type T, with error checking. */ | 112 | /* Allocate memory for N elements of type T, with error checking. */ |
| 78 | /* extern t *XNMALLOC (size_t n, typename t); */ | 113 | /* extern t *XNMALLOC (size_t n, typename t); */ |
| 79 | #define XNMALLOC(n, t) \ | 114 | # define XNMALLOC(n, t) \ |
| 80 | ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t)))) | 115 | ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t)))) |
| 81 | 116 | ||
| 82 | /* Allocate an object of type T dynamically, with error checking, | 117 | /* Allocate an object of type T dynamically, with error checking, |
| 83 | and zero it. */ | 118 | and zero it. */ |
| 84 | /* extern t *XZALLOC (typename t); */ | 119 | /* extern t *XZALLOC (typename t); */ |
| 85 | #define XZALLOC(t) ((t *) xzalloc (sizeof (t))) | 120 | # define XZALLOC(t) ((t *) xzalloc (sizeof (t))) |
| 86 | 121 | ||
| 87 | /* Allocate memory for N elements of type T, with error checking, | 122 | /* Allocate memory for N elements of type T, with error checking, |
| 88 | and zero it. */ | 123 | and zero it. */ |
| 89 | /* extern t *XCALLOC (size_t n, typename t); */ | 124 | /* extern t *XCALLOC (size_t n, typename t); */ |
| 90 | #define XCALLOC(n, t) \ | 125 | # define XCALLOC(n, t) \ |
| 91 | ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t)))) | 126 | ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t)))) |
| 92 | 127 | ||
| 93 | 128 | ||
| 94 | /* Allocate an array of N objects, each with S bytes of memory, | 129 | /* Allocate an array of N objects, each with S bytes of memory, |
| 95 | dynamically, with error checking. S must be nonzero. */ | 130 | dynamically, with error checking. S must be nonzero. */ |
| 96 | 131 | ||
| 97 | XALLOC_INLINE void *xnmalloc (size_t n, size_t s) | 132 | void *xnmalloc (size_t n, size_t s) |
| 98 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)); | 133 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE |
| 99 | XALLOC_INLINE void * | 134 | _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)) _GL_ATTRIBUTE_RETURNS_NONNULL; |
| 100 | xnmalloc (size_t n, size_t s) | ||
| 101 | { | ||
| 102 | if (xalloc_oversized (n, s)) | ||
| 103 | xalloc_die (); | ||
| 104 | return xmalloc (n * s); | ||
| 105 | } | ||
| 106 | 135 | ||
| 136 | /* FIXME: Deprecate this in favor of xreallocarray? */ | ||
| 107 | /* Change the size of an allocated block of memory P to an array of N | 137 | /* Change the size of an allocated block of memory P to an array of N |
| 108 | objects each of S bytes, with error checking. S must be nonzero. */ | 138 | objects each of S bytes, with error checking. S must be nonzero. */ |
| 109 | 139 | ||
| 110 | XALLOC_INLINE void *xnrealloc (void *p, size_t n, size_t s) | 140 | XALLOC_INLINE void *xnrealloc (void *p, size_t n, size_t s) |
| 111 | _GL_ATTRIBUTE_ALLOC_SIZE ((2, 3)); | 141 | _GL_ATTRIBUTE_ALLOC_SIZE ((2, 3)); |
| 112 | XALLOC_INLINE void * | 142 | XALLOC_INLINE void * |
| 113 | xnrealloc (void *p, size_t n, size_t s) | 143 | xnrealloc (void *p, size_t n, size_t s) |
| 114 | { | 144 | { |
| 115 | if (xalloc_oversized (n, s)) | 145 | return xreallocarray (p, n, s); |
| 116 | xalloc_die (); | ||
| 117 | return xrealloc (p, n * s); | ||
| 118 | } | ||
| 119 | |||
| 120 | /* If P is null, allocate a block of at least *PN such objects; | ||
| 121 | otherwise, reallocate P so that it contains more than *PN objects | ||
| 122 | each of S bytes. *PN must be nonzero unless P is null, and S must | ||
| 123 | be nonzero. Set *PN to the new number of objects, and return the | ||
| 124 | pointer to the new block. *PN is never set to zero, and the | ||
| 125 | returned pointer is never null. | ||
| 126 | |||
| 127 | Repeated reallocations are guaranteed to make progress, either by | ||
| 128 | allocating an initial block with a nonzero size, or by allocating a | ||
| 129 | larger block. | ||
| 130 | |||
| 131 | In the following implementation, nonzero sizes are increased by a | ||
| 132 | factor of approximately 1.5 so that repeated reallocations have | ||
| 133 | O(N) overall cost rather than O(N**2) cost, but the | ||
| 134 | specification for this function does not guarantee that rate. | ||
| 135 | |||
| 136 | Here is an example of use: | ||
| 137 | |||
| 138 | int *p = NULL; | ||
| 139 | size_t used = 0; | ||
| 140 | size_t allocated = 0; | ||
| 141 | |||
| 142 | void | ||
| 143 | append_int (int value) | ||
| 144 | { | ||
| 145 | if (used == allocated) | ||
| 146 | p = x2nrealloc (p, &allocated, sizeof *p); | ||
| 147 | p[used++] = value; | ||
| 148 | } | ||
| 149 | |||
| 150 | This causes x2nrealloc to allocate a block of some nonzero size the | ||
| 151 | first time it is called. | ||
| 152 | |||
| 153 | To have finer-grained control over the initial size, set *PN to a | ||
| 154 | nonzero value before calling this function with P == NULL. For | ||
| 155 | example: | ||
| 156 | |||
| 157 | int *p = NULL; | ||
| 158 | size_t used = 0; | ||
| 159 | size_t allocated = 0; | ||
| 160 | size_t allocated1 = 1000; | ||
| 161 | |||
| 162 | void | ||
| 163 | append_int (int value) | ||
| 164 | { | ||
| 165 | if (used == allocated) | ||
| 166 | { | ||
| 167 | p = x2nrealloc (p, &allocated1, sizeof *p); | ||
| 168 | allocated = allocated1; | ||
| 169 | } | ||
| 170 | p[used++] = value; | ||
| 171 | } | ||
| 172 | |||
| 173 | */ | ||
| 174 | |||
| 175 | XALLOC_INLINE void * | ||
| 176 | x2nrealloc (void *p, size_t *pn, size_t s) | ||
| 177 | { | ||
| 178 | size_t n = *pn; | ||
| 179 | |||
| 180 | if (! p) | ||
| 181 | { | ||
| 182 | if (! n) | ||
| 183 | { | ||
| 184 | /* The approximate size to use for initial small allocation | ||
| 185 | requests, when the invoking code specifies an old size of | ||
| 186 | zero. This is the largest "small" request for the GNU C | ||
| 187 | library malloc. */ | ||
| 188 | enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 }; | ||
| 189 | |||
| 190 | n = DEFAULT_MXFAST / s; | ||
| 191 | n += !n; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | else | ||
| 195 | { | ||
| 196 | /* Set N = ceil (1.5 * N) so that progress is made if N == 1. | ||
| 197 | Check for overflow, so that N * S stays in size_t range. | ||
| 198 | The check is slightly conservative, but an exact check isn't | ||
| 199 | worth the trouble. */ | ||
| 200 | if ((size_t) -1 / 3 * 2 / s <= n) | ||
| 201 | xalloc_die (); | ||
| 202 | n += (n + 1) / 2; | ||
| 203 | } | ||
| 204 | |||
| 205 | *pn = n; | ||
| 206 | return xrealloc (p, n * s); | ||
| 207 | } | 146 | } |
| 208 | 147 | ||
| 209 | /* Return a pointer to a new buffer of N bytes. This is like xmalloc, | 148 | /* Return a pointer to a new buffer of N bytes. This is like xmalloc, |
| 210 | except it returns char *. */ | 149 | except it returns char *. */ |
| 211 | 150 | ||
| 212 | XALLOC_INLINE char *xcharalloc (size_t n) | 151 | char *xcharalloc (size_t n) |
| 213 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1)); | 152 | _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE |
| 214 | XALLOC_INLINE char * | 153 | _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_RETURNS_NONNULL; |
| 215 | xcharalloc (size_t n) | 154 | |
| 216 | { | 155 | #endif /* GNULIB_XALLOC */ |
| 217 | return XNMALLOC (n, char); | 156 | |
| 218 | } | ||
| 219 | 157 | ||
| 220 | #ifdef __cplusplus | 158 | #ifdef __cplusplus |
| 221 | } | 159 | } |
| 160 | #endif | ||
| 161 | |||
| 162 | |||
| 163 | #if GNULIB_XALLOC && defined __cplusplus | ||
| 222 | 164 | ||
| 223 | /* C++ does not allow conversions from void * to other pointer types | 165 | /* C++ does not allow conversions from void * to other pointer types |
| 224 | without a cast. Use templates to work around the problem when | 166 | without a cast. Use templates to work around the problem when |
| @@ -231,9 +173,16 @@ xrealloc (T *p, size_t s) | |||
| 231 | } | 173 | } |
| 232 | 174 | ||
| 233 | template <typename T> inline T * | 175 | template <typename T> inline T * |
| 176 | xreallocarray (T *p, size_t n, size_t s) | ||
| 177 | { | ||
| 178 | return (T *) xreallocarray ((void *) p, n, s); | ||
| 179 | } | ||
| 180 | |||
| 181 | /* FIXME: Deprecate this in favor of xreallocarray? */ | ||
| 182 | template <typename T> inline T * | ||
| 234 | xnrealloc (T *p, size_t n, size_t s) | 183 | xnrealloc (T *p, size_t n, size_t s) |
| 235 | { | 184 | { |
| 236 | return (T *) xnrealloc ((void *) p, n, s); | 185 | return xreallocarray (p, n, s); |
| 237 | } | 186 | } |
| 238 | 187 | ||
| 239 | template <typename T> inline T * | 188 | template <typename T> inline T * |
| @@ -254,7 +203,9 @@ xmemdup (T const *p, size_t s) | |||
| 254 | return (T *) xmemdup ((void const *) p, s); | 203 | return (T *) xmemdup ((void const *) p, s); |
| 255 | } | 204 | } |
| 256 | 205 | ||
| 257 | #endif | 206 | #endif /* GNULIB_XALLOC && C++ */ |
| 207 | |||
| 258 | 208 | ||
| 209 | _GL_INLINE_HEADER_END | ||
| 259 | 210 | ||
| 260 | #endif /* !XALLOC_H_ */ | 211 | #endif /* !XALLOC_H_ */ |
