]> eyrie.org Git - kerberos/krb5-strength.git/blob - util/xmalloc.c
New upstream version 3.1
[kerberos/krb5-strength.git] / util / xmalloc.c
1 /*
2  * malloc routines with failure handling.
3  *
4  * Usage:
5  *
6  *      extern xmalloc_handler_t memory_error;
7  *      extern const char *string;
8  *      char *buffer;
9  *      va_list args;
10  *
11  *      xmalloc_error_handler = memory_error;
12  *      buffer = xmalloc(1024);
13  *      xrealloc(buffer, 2048);
14  *      free(buffer);
15  *      buffer = xcalloc(1, 1024);
16  *      free(buffer);
17  *      buffer = xstrdup(string);
18  *      free(buffer);
19  *      buffer = xstrndup(string, 25);
20  *      free(buffer);
21  *      xasprintf(&buffer, "%s", "some string");
22  *      free(buffer);
23  *      xvasprintf(&buffer, "%s", args);
24  *
25  * xmalloc, xcalloc, xrealloc, and xstrdup behave exactly like their C library
26  * counterparts without the leading x except that they will never return NULL.
27  * Instead, on error, they call xmalloc_error_handler, passing it the name of
28  * the function whose memory allocation failed, the amount of the allocation,
29  * and the file and line number where the allocation function was invoked
30  * (from __FILE__ and __LINE__).  This function may do whatever it wishes,
31  * such as some action to free up memory or a call to sleep to hope that
32  * system resources return.  If the handler returns, the interrupted memory
33  * allocation function will try its allocation again (calling the handler
34  * again if it still fails).
35  *
36  * xreallocarray behaves the same as the OpenBSD reallocarray function but for
37  * the same error checking, which in turn is the same as realloc but with
38  * calloc-style arguments and size overflow checking.
39  *
40  * xstrndup behaves like xstrdup but only copies the given number of
41  * characters.  It allocates an additional byte over its second argument and
42  * always nul-terminates the string.
43  *
44  * xasprintf and xvasprintf behave just like their GNU glibc library
45  * implementations except that they do the same checking as described above.
46  * xasprintf will only be able to provide accurate file and line information
47  * on systems that support variadic macros.
48  *
49  * The default error handler, if none is set by the caller, prints an error
50  * message to stderr and exits with exit status 1.  An error handler must take
51  * a const char * (function name), size_t (bytes allocated), const char *
52  * (file), and int (line).
53  *
54  * xmalloc will return a pointer to a valid memory region on an xmalloc of 0
55  * bytes, ensuring this by allocating space for one character instead of 0
56  * bytes.
57  *
58  * The functions defined here are actually x_malloc, x_realloc, etc.  The
59  * header file defines macros named xmalloc, etc. that pass the file name and
60  * line number to these functions.
61  *
62  * The canonical version of this file is maintained in the rra-c-util package,
63  * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
64  *
65  * Copyright 2015 Russ Allbery <eagle@eyrie.org>
66  * Copyright 2012, 2013, 2014
67  *     The Board of Trustees of the Leland Stanford Junior University
68  * Copyright (c) 2004, 2005, 2006
69  *     by Internet Systems Consortium, Inc. ("ISC")
70  * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
71  *     2002, 2003 by The Internet Software Consortium and Rich Salz
72  *
73  * This code is derived from software contributed to the Internet Software
74  * Consortium by Rich Salz.
75  *
76  * Permission to use, copy, modify, and distribute this software for any
77  * purpose with or without fee is hereby granted, provided that the above
78  * copyright notice and this permission notice appear in all copies.
79  *
80  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
81  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
82  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
83  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
84  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
85  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
86  * PERFORMANCE OF THIS SOFTWARE.
87  */
88
89 #include <config.h>
90 #include <portable/system.h>
91
92 #include <util/messages.h>
93 #include <util/xmalloc.h>
94
95
96 /*
97  * The default error handler.
98  */
99 void
100 xmalloc_fail(const char *function, size_t size, const char *file, int line)
101 {
102     if (size == 0)
103         sysdie("failed to format output with %s at %s line %d", function,
104                file, line);
105     else
106         sysdie("failed to %s %lu bytes at %s line %d", function,
107                (unsigned long) size, file, line);
108 }
109
110 /* Assign to this variable to choose a handler other than the default. */
111 xmalloc_handler_type xmalloc_error_handler = xmalloc_fail;
112
113
114 void *
115 x_malloc(size_t size, const char *file, int line)
116 {
117     void *p;
118     size_t real_size;
119
120     real_size = (size > 0) ? size : 1;
121     p = malloc(real_size);
122     while (p == NULL) {
123         (*xmalloc_error_handler)("malloc", size, file, line);
124         p = malloc(real_size);
125     }
126     return p;
127 }
128
129
130 void *
131 x_calloc(size_t n, size_t size, const char *file, int line)
132 {
133     void *p;
134
135     n = (n > 0) ? n : 1;
136     size = (size > 0) ? size : 1;
137     p = calloc(n, size);
138     while (p == NULL) {
139         (*xmalloc_error_handler)("calloc", n * size, file, line);
140         p = calloc(n, size);
141     }
142     return p;
143 }
144
145
146 void *
147 x_realloc(void *p, size_t size, const char *file, int line)
148 {
149     void *newp;
150
151     newp = realloc(p, size);
152     while (newp == NULL && size > 0) {
153         (*xmalloc_error_handler)("realloc", size, file, line);
154         newp = realloc(p, size);
155     }
156     return newp;
157 }
158
159
160 void *
161 x_reallocarray(void *p, size_t n, size_t size, const char *file, int line)
162 {
163     void *newp;
164
165     newp = reallocarray(p, n, size);
166     while (newp == NULL && size > 0 && n > 0) {
167         (*xmalloc_error_handler)("reallocarray", n * size, file, line);
168         newp = reallocarray(p, n, size);
169     }
170     return newp;
171 }
172
173
174 char *
175 x_strdup(const char *s, const char *file, int line)
176 {
177     char *p;
178     size_t len;
179
180     len = strlen(s) + 1;
181     p = malloc(len);
182     while (p == NULL) {
183         (*xmalloc_error_handler)("strdup", len, file, line);
184         p = malloc(len);
185     }
186     memcpy(p, s, len);
187     return p;
188 }
189
190
191 /*
192  * Avoid using the system strndup function since it may not exist (on Mac OS
193  * X, for example), and there's no need to introduce another portability
194  * requirement.
195  */
196 char *
197 x_strndup(const char *s, size_t size, const char *file, int line)
198 {
199     const char *p;
200     size_t length;
201     char *copy;
202
203     /* Don't assume that the source string is nul-terminated. */
204     for (p = s; (size_t) (p - s) < size && *p != '\0'; p++)
205         ;
206     length = p - s;
207     copy = malloc(length + 1);
208     while (copy == NULL) {
209         (*xmalloc_error_handler)("strndup", length + 1, file, line);
210         copy = malloc(length + 1);
211     }
212     memcpy(copy, s, length);
213     copy[length] = '\0';
214     return copy;
215 }
216
217
218 void
219 x_vasprintf(char **strp, const char *fmt, va_list args, const char *file,
220             int line)
221 {
222     va_list args_copy;
223     int status;
224
225     va_copy(args_copy, args);
226     status = vasprintf(strp, fmt, args_copy);
227     va_end(args_copy);
228     while (status < 0) {
229         va_copy(args_copy, args);
230         status = vsnprintf(NULL, 0, fmt, args_copy);
231         va_end(args_copy);
232         status = (status < 0) ? 0 : status + 1;
233         (*xmalloc_error_handler)("vasprintf", status, file, line);
234         va_copy(args_copy, args);
235         status = vasprintf(strp, fmt, args_copy);
236         va_end(args_copy);
237     }
238 }
239
240
241 #if HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS
242 void
243 x_asprintf(char **strp, const char *file, int line, const char *fmt, ...)
244 {
245     va_list args, args_copy;
246     int status;
247
248     va_start(args, fmt);
249     va_copy(args_copy, args);
250     status = vasprintf(strp, fmt, args_copy);
251     va_end(args_copy);
252     while (status < 0) {
253         va_copy(args_copy, args);
254         status = vsnprintf(NULL, 0, fmt, args_copy);
255         va_end(args_copy);
256         status = (status < 0) ? 0 : status + 1;
257         (*xmalloc_error_handler)("asprintf", status, file, line);
258         va_copy(args_copy, args);
259         status = vasprintf(strp, fmt, args_copy);
260         va_end(args_copy);
261     }
262     va_end(args);
263 }
264 #else /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */
265 void
266 x_asprintf(char **strp, const char *fmt, ...)
267 {
268     va_list args, args_copy;
269     int status;
270
271     va_start(args, fmt);
272     va_copy(args_copy, args);
273     status = vasprintf(strp, fmt, args_copy);
274     va_end(args_copy);
275     while (status < 0) {
276         va_copy(args_copy, args);
277         status = vsnprintf(NULL, 0, fmt, args_copy);
278         va_end(args_copy);
279         status = (status < 0) ? 0 : status + 1;
280         (*xmalloc_error_handler)("asprintf", status, __FILE__, __LINE__);
281         va_copy(args_copy, args);
282         status = vasprintf(strp, fmt, args_copy);
283         va_end(args_copy);
284     }
285     va_end(args);
286 }
287 #endif /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */