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 da7c4b6..f373c2f 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_ */ |