source: web/old/remctl-2.14/util/xmalloc.c @ f6f3e91

web
Last change on this file since f6f3e91 was f6f3e91, checked in by Jessica B. Hamrick <jhamrick@…>, 15 years ago

Preserve directory hierarchy (not sure what happened to it)

  • Property mode set to 100644
File size: 6.4 KB
Line 
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 * Copyright (c) 2004, 2005, 2006
59 *     by Internet Systems Consortium, Inc. ("ISC")
60 * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
61 *     2002, 2003 by The Internet Software Consortium and Rich Salz
62 *
63 * See LICENSE for licensing terms.
64 */
65
66#include <config.h>
67#include <portable/system.h>
68
69#include <errno.h>
70
71#include <util/util.h>
72
73
74/*
75 * The default error handler.
76 */
77void
78xmalloc_fail(const char *function, size_t size, const char *file, int line)
79{
80    sysdie("failed to %s %lu bytes at %s line %d", function,
81           (unsigned long) size, file, line);
82}
83
84/* Assign to this variable to choose a handler other than the default. */
85xmalloc_handler_type xmalloc_error_handler = xmalloc_fail;
86
87
88void *
89x_malloc(size_t size, const char *file, int line)
90{
91    void *p;
92    size_t real_size;
93
94    real_size = (size > 0) ? size : 1;
95    p = malloc(real_size);
96    while (p == NULL) {
97        (*xmalloc_error_handler)("malloc", size, file, line);
98        p = malloc(real_size);
99    }
100    return p;
101}
102
103
104void *
105x_calloc(size_t n, size_t size, const char *file, int line)
106{
107    void *p;
108
109    n = (n > 0) ? n : 1;
110    size = (size > 0) ? size : 1;
111    p = calloc(n, size);
112    while (p == NULL) {
113        (*xmalloc_error_handler)("calloc", n * size, file, line);
114        p = calloc(n, size);
115    }
116    return p;
117}
118
119
120void *
121x_realloc(void *p, size_t size, const char *file, int line)
122{
123    void *newp;
124
125    newp = realloc(p, size);
126    while (newp == NULL && size > 0) {
127        (*xmalloc_error_handler)("realloc", size, file, line);
128        newp = realloc(p, size);
129    }
130    return newp;
131}
132
133
134char *
135x_strdup(const char *s, const char *file, int line)
136{
137    char *p;
138    size_t len;
139
140    len = strlen(s) + 1;
141    p = malloc(len);
142    while (p == NULL) {
143        (*xmalloc_error_handler)("strdup", len, file, line);
144        p = malloc(len);
145    }
146    memcpy(p, s, len);
147    return p;
148}
149
150
151char *
152x_strndup(const char *s, size_t size, const char *file, int line)
153{
154    char *p;
155
156    p = malloc(size + 1);
157    while (p == NULL) {
158        (*xmalloc_error_handler)("strndup", size + 1, file, line);
159        p = malloc(size + 1);
160    }
161    memcpy(p, s, size);
162    p[size] = '\0';
163    return p;
164}
165
166
167int
168x_vasprintf(char **strp, const char *fmt, va_list args, const char *file,
169            int line)
170{
171    va_list args_copy;
172    int status;
173
174    va_copy(args_copy, args);
175    status = vasprintf(strp, fmt, args_copy);
176    va_end(args_copy);
177    while (status < 0 && errno == ENOMEM) {
178        va_copy(args_copy, args);
179        status = vsnprintf(NULL, 0, fmt, args_copy);
180        va_end(args_copy);
181        (*xmalloc_error_handler)("vasprintf", status + 1, file, line);
182        va_copy(args_copy, args);
183        status = vasprintf(strp, fmt, args_copy);
184        va_end(args_copy);
185    }
186    return status;
187}
188
189
190#if HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS
191int
192x_asprintf(char **strp, const char *file, int line, const char *fmt, ...)
193{
194    va_list args, args_copy;
195    int status;
196
197    va_start(args, fmt);
198    va_copy(args_copy, args);
199    status = vasprintf(strp, fmt, args_copy);
200    va_end(args_copy);
201    while (status < 0 && errno == ENOMEM) {
202        va_copy(args_copy, args);
203        status = vsnprintf(NULL, 0, fmt, args_copy);
204        va_end(args_copy);
205        (*xmalloc_error_handler)("asprintf", status + 1, file, line);
206        va_copy(args_copy, args);
207        status = vasprintf(strp, fmt, args_copy);
208        va_end(args_copy);
209    }
210    return status;
211}
212#else /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */
213int
214x_asprintf(char **strp, const char *fmt, ...)
215{
216    va_list args, args_copy;
217    int status;
218
219    va_start(args, fmt);
220    va_copy(args_copy, args);
221    status = vasprintf(strp, fmt, args_copy);
222    va_end(args_copy);
223    while (status < 0 && errno == ENOMEM) {
224        va_copy(args_copy, args);
225        status = vsnprintf(NULL, 0, fmt, args_copy);
226        va_end(args_copy);
227        (*xmalloc_error_handler)("asprintf", status + 1, __FILE__, __LINE__);
228        va_copy(args_copy, args);
229        status = vasprintf(strp, fmt, args_copy);
230        va_end(args_copy);
231    }
232    return status;
233}
234#endif /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */
Note: See TracBrowser for help on using the repository browser.