2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: alloc.c,v 1.35 2005/12/21 19:07:49 paddy_s Exp $
29 * Memory allocators with error handling. If the allocation fails,
30 * errordump() is called, relieving the caller from checking the return
37 static char *internal_vstralloc P((const char *, va_list));
40 *=====================================================================
41 * debug_caller_loc -- keep track of all allocation callers
43 * const char *debug_caller_loc(const char *file, int line)
45 * entry: file = source file
47 * exit: a string like "genversion.c@999"
49 * The debug malloc library has a concept of a call stack that can be used
50 * to fine tune what was running when a particular allocation was done.
51 * We use it to tell who called our various allocation wrappers since
52 * it wouldn't do much good to tell us a problem happened because of
53 * the malloc call in alloc (they are all from there at some point).
55 * But the library expects the string passed to malloc_enter/malloc_leave
56 * to be static, so we build a linked list of each one we get (there are
57 * not really that many during a given execution). When we get a repeat
58 * we return the previously allocated string. For a bit of performance,
59 * we keep the list in least recently used order, which helps because
60 * the calls to us come in pairs (one for malloc_enter and one right
61 * after for malloc_leave).
62 *=====================================================================
66 debug_caller_loc(file, line)
72 LIST_ENTRY(loc_str) le;
74 static LIST_HEAD(, loc_str) root = LIST_HEAD_INITIALIZER(root);
75 static char loc[256]; /* big enough for filename@lineno */
78 if ((p = strrchr(file, '/')) != NULL)
79 file = p + 1; /* just the last path element */
81 snprintf(loc, sizeof(loc), "%s@%d", file, line);
83 for (ls = LIST_FIRST(&root); ls != NULL; ls = LIST_NEXT(ls, le)) {
84 if (strcmp(loc, ls->str) == 0) {
85 if (ls != LIST_FIRST(&root)) {
87 * This is a repeat and was not at the head of the list.
88 * Unlink it and move it to the front.
91 LIST_INSERT_HEAD(&root, ls, le);
98 * This is a new entry. Put it at the head of the list.
100 ls = malloc(sizeof(*ls));
102 return ("??"); /* not much better than abort */
103 ls->str = malloc(strlen(loc) + 1);
104 if (ls->str == NULL) {
106 return ("??"); /* not much better than abort */
108 strcpy(ls->str, loc);
110 malloc_mark(ls->str);
111 LIST_INSERT_HEAD(&root, ls, le);
116 *=====================================================================
117 * Save the current source line for vstralloc/newvstralloc.
119 * int debug_alloc_push (char *s, int l)
121 * entry: s = source file
125 * See the comments in amanda.h about what this is used for.
126 *=====================================================================
129 #define DEBUG_ALLOC_SAVE_MAX 10
134 } debug_alloc_loc_info[DEBUG_ALLOC_SAVE_MAX];
135 static int debug_alloc_ptr = 0;
137 static char *saved_file;
138 static int saved_line;
141 debug_alloc_push (s, l)
145 debug_alloc_loc_info[debug_alloc_ptr].file = s;
146 debug_alloc_loc_info[debug_alloc_ptr].line = l;
147 debug_alloc_ptr = (debug_alloc_ptr + 1) % DEBUG_ALLOC_SAVE_MAX;
152 *=====================================================================
153 * Pop the current source line information for vstralloc/newvstralloc.
155 * int debug_alloc_pop (void)
160 * See the comments in amanda.h about what this is used for.
161 *=====================================================================
168 (debug_alloc_ptr + DEBUG_ALLOC_SAVE_MAX - 1) % DEBUG_ALLOC_SAVE_MAX;
169 saved_file = debug_alloc_loc_info[debug_alloc_ptr].file;
170 saved_line = debug_alloc_loc_info[debug_alloc_ptr].line;
174 * alloc - a wrapper for malloc.
177 debug_alloc(s, l, size)
184 malloc_enter(debug_caller_loc(s, l));
185 addr = (void *)malloc(max(size, 1));
187 errordump("%s@%d: memory allocation failed (%u bytes requested)",
192 malloc_leave(debug_caller_loc(s, l));
198 * newalloc - free existing buffer and then alloc a new one.
201 debug_newalloc(s, l, old, size)
209 malloc_enter(debug_caller_loc(s, l));
210 addr = debug_alloc(s, l, size);
212 malloc_leave(debug_caller_loc(s, l));
218 * stralloc - copies the given string into newly allocated memory.
219 * Just like strdup()!
222 debug_stralloc(s, l, str)
229 malloc_enter(debug_caller_loc(s, l));
230 addr = debug_alloc(s, l, strlen(str) + 1);
232 malloc_leave(debug_caller_loc(s, l));
236 /* vstrextend -- Extends the existing string by appending the other
238 arglist_function(char *vstrextend,
242 char *keep = *oldstr;
245 arglist_start(ap, oldstr);
249 *oldstr = internal_vstralloc(*oldstr, ap);
257 * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
260 * The MAX_STR_ARGS limit is purely an efficiency issue so we do not have
261 * to scan the strings more than necessary.
264 #define MAX_VSTRALLOC_ARGS 32
267 internal_vstralloc(str, argp)
275 const char *arg[MAX_VSTRALLOC_ARGS+1];
276 size_t len[MAX_VSTRALLOC_ARGS+1];
281 return NULL; /* probably will not happen */
287 total_len = len[a] = l;
290 while ((next = arglist_val(argp, char *)) != NULL) {
291 if ((l = strlen(next)) == 0) {
292 continue; /* minor optimisation */
294 if (a >= MAX_VSTRALLOC_ARGS) {
295 errordump("%s@%d: more than %d arg%s to vstralloc",
296 saved_file ? saved_file : "(unknown)",
297 saved_file ? saved_line : -1,
299 (MAX_VSTRALLOC_ARGS == 1) ? "" : "s");
309 next = result = debug_alloc(saved_file, saved_line, total_len+1);
310 for (a = 0; (s = arg[a]) != NULL; a++) {
311 memcpy(next, s, len[a]);
321 * vstralloc - copies multiple strings into newly allocated memory.
323 arglist_function(char *debug_vstralloc, const char *, str)
329 malloc_enter(debug_caller_loc(saved_file, saved_line));
330 arglist_start(argp, str);
331 result = internal_vstralloc(str, argp);
333 malloc_leave(debug_caller_loc(saved_file, saved_line));
339 * newstralloc - free existing string and then stralloc a new one.
342 debug_newstralloc(s, l, oldstr, newstr)
350 malloc_enter(debug_caller_loc(s, l));
351 addr = debug_stralloc(s, l, newstr);
353 malloc_leave(debug_caller_loc(s, l));
359 * newvstralloc - free existing string and then vstralloc a new one.
361 arglist_function1(char *debug_newvstralloc,
371 malloc_enter(debug_caller_loc(saved_file, saved_line));
372 arglist_start(argp, newstr);
373 result = internal_vstralloc(newstr, argp);
376 malloc_leave(debug_caller_loc(saved_file, saved_line));
382 * safe_env - build a "safe" environment list.
387 static char *safe_env_list[] = {
400 * If the initial environment pointer malloc fails, set up to
401 * pass back a pointer to the NULL string pointer at the end of
402 * safe_env_list so our result is always a valid, although possibly
403 * empty, environment list.
405 #define SAFE_ENV_CNT (sizeof(safe_env_list) / sizeof(*safe_env_list))
406 char **envp = safe_env_list + SAFE_ENV_CNT - 1;
414 if ((q = (char **)malloc(sizeof(safe_env_list))) != NULL) {
416 for (p = safe_env_list; *p != NULL; p++) {
417 if ((v = getenv(*p)) == NULL) {
418 continue; /* no variable to dup */
420 l1 = strlen(*p); /* variable name w/o null */
421 l2 = strlen(v) + 1; /* include null byte here */
422 if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
423 break; /* out of memory */
425 *q++ = s; /* save the new pointer */
426 memcpy(s, *p, l1); /* left hand side */
429 memcpy(s, v, l2); /* right hand side and null */
431 *q = NULL; /* terminate the list */
437 * amtable_alloc -- (re)allocate enough space for some number of elements.
439 * input: table -- pointer to pointer to table
440 * current -- pointer to current number of elements
441 * elsize -- size of a table element
442 * count -- desired number of elements
443 * bump -- round up factor
444 * init_func -- optional element initialization function
445 * output: table -- possibly adjusted to point to new table area
446 * current -- possibly adjusted to new number of elements
450 debug_amtable_alloc(s, l, table, current, elsize, count, bump, init_func)
458 void (*init_func)(void *);
464 if (count >= *current) {
465 table_count_new = ((count + bump) / bump) * bump;
466 table_new = debug_alloc(s, l, table_count_new * elsize);
468 memcpy(table_new, *table, *current * elsize);
472 memset(((char *)*table) + *current * elsize,
474 (table_count_new - *current) * elsize);
475 if (init_func != NULL) {
476 for (i = *current; i < table_count_new; i++) {
477 (*init_func)(((char *)*table) + i * elsize);
480 *current = table_count_new;
486 * amtable_free -- release a table.
488 * input: table -- pointer to pointer to table
489 * current -- pointer to current number of elements
490 * output: table -- possibly adjusted to point to new table area
491 * current -- possibly adjusted to new number of elements
495 amtable_free(table, current)