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