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.37 2006/07/05 10:41:32 martinea 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(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 *=====================================================================
73 LIST_ENTRY(loc_str) le;
75 static LIST_HEAD(, loc_str) root = LIST_HEAD_INITIALIZER(root);
76 static char loc[256]; /* big enough for filename@lineno */
79 if ((p = strrchr(file, '/')) != NULL)
80 file = p + 1; /* just the last path element */
82 snprintf(loc, SIZEOF(loc), "%s@%d", file, line);
84 for (ls = LIST_FIRST(&root); ls != NULL; ls = LIST_NEXT(ls, le)) {
85 if (strcmp(loc, ls->str) == 0) {
86 if (ls != LIST_FIRST(&root)) {
88 * This is a repeat and was not at the head of the list.
89 * Unlink it and move it to the front.
92 LIST_INSERT_HEAD(&root, ls, le);
99 * This is a new entry. Put it at the head of the list.
101 ls = malloc(SIZEOF(*ls));
103 return ("??"); /* not much better than abort */
104 ls->str = malloc(strlen(loc) + 1);
105 if (ls->str == NULL) {
107 return ("??"); /* not much better than abort */
109 strcpy(ls->str, loc);
111 malloc_mark(ls->str);
112 LIST_INSERT_HEAD(&root, ls, le);
117 *=====================================================================
118 * Save the current source line for vstralloc/newvstralloc.
120 * int debug_alloc_push (char *s, int l)
122 * entry: s = source file
126 * See the comments in amanda.h about what this is used for.
127 *=====================================================================
130 #define DEBUG_ALLOC_SAVE_MAX 10
135 } debug_alloc_loc_info[DEBUG_ALLOC_SAVE_MAX];
136 static int debug_alloc_ptr = 0;
138 static char *saved_file;
139 static int saved_line;
146 debug_alloc_loc_info[debug_alloc_ptr].file = s;
147 debug_alloc_loc_info[debug_alloc_ptr].line = l;
148 debug_alloc_ptr = (debug_alloc_ptr + 1) % DEBUG_ALLOC_SAVE_MAX;
153 *=====================================================================
154 * Pop the current source line information for vstralloc/newvstralloc.
156 * int debug_alloc_pop (void)
161 * See the comments in amanda.h about what this is used for.
162 *=====================================================================
166 debug_alloc_pop(void)
169 (debug_alloc_ptr + DEBUG_ALLOC_SAVE_MAX - 1) % DEBUG_ALLOC_SAVE_MAX;
170 saved_file = debug_alloc_loc_info[debug_alloc_ptr].file;
171 saved_line = debug_alloc_loc_info[debug_alloc_ptr].line;
175 * alloc - a wrapper for malloc.
185 malloc_enter(debug_caller_loc(s, l));
186 addr = (void *)malloc(max(size, 1));
188 errordump("%s@%d: memory allocation failed (" SIZE_T_FMT " bytes requested)",
191 (SIZE_T_FMT_TYPE)size);
194 malloc_leave(debug_caller_loc(s, l));
200 * newalloc - free existing buffer and then alloc a new one.
211 malloc_enter(debug_caller_loc(s, l));
212 addr = debug_alloc(s, l, size);
214 malloc_leave(debug_caller_loc(s, l));
220 * stralloc - copies the given string into newly allocated memory.
221 * Just like strdup()!
231 malloc_enter(debug_caller_loc(s, l));
232 addr = debug_alloc(s, l, strlen(str) + 1);
234 malloc_leave(debug_caller_loc(s, l));
238 /* vstrextend -- Extends the existing string by appending the other
245 char *keep = *oldstr;
248 arglist_start(ap, oldstr);
252 *oldstr = internal_vstralloc(*oldstr, ap);
261 * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
264 * The MAX_STR_ARGS limit is purely an efficiency issue so we do not have
265 * to scan the strings more than necessary.
268 #define MAX_VSTRALLOC_ARGS 32
279 const char *arg[MAX_VSTRALLOC_ARGS+1];
280 size_t len[MAX_VSTRALLOC_ARGS+1];
284 errordump("internal_vstralloc: str is NULL");
291 total_len = len[a] = l;
294 while ((next = arglist_val(argp, char *)) != NULL) {
295 if ((l = strlen(next)) == 0) {
296 continue; /* minor optimisation */
298 if (a >= MAX_VSTRALLOC_ARGS) {
299 errordump("%s@%d: more than %d args to vstralloc",
300 saved_file ? saved_file : "(unknown)",
301 saved_file ? saved_line : -1,
311 result = debug_alloc(saved_file, saved_line, total_len+1);
314 for (b = 0; b < a; b++) {
315 memcpy(next, arg[b], len[b]);
325 * vstralloc - copies multiple strings into newly allocated memory.
328 char *debug_vstralloc,
335 malloc_enter(debug_caller_loc(saved_file, saved_line));
336 arglist_start(argp, str);
337 result = internal_vstralloc(str, argp);
339 malloc_leave(debug_caller_loc(saved_file, saved_line));
345 * newstralloc - free existing string and then stralloc a new one.
356 malloc_enter(debug_caller_loc(s, l));
357 addr = debug_stralloc(s, l, newstr);
359 malloc_leave(debug_caller_loc(s, l));
365 * newvstralloc - free existing string and then vstralloc a new one.
368 char *debug_newvstralloc,
370 const char *, newstr)
376 malloc_enter(debug_caller_loc(saved_file, saved_line));
377 arglist_start(argp, newstr);
378 result = internal_vstralloc(newstr, argp);
381 malloc_leave(debug_caller_loc(saved_file, saved_line));
387 * safe_env - build a "safe" environment list.
392 static char *safe_env_list[] = {
405 * If the initial environment pointer malloc fails, set up to
406 * pass back a pointer to the NULL string pointer at the end of
407 * safe_env_list so our result is always a valid, although possibly
408 * empty, environment list.
410 #define SAFE_ENV_CNT (size_t)(sizeof(safe_env_list) / sizeof(*safe_env_list))
411 char **envp = safe_env_list + SAFE_ENV_CNT - 1;
419 if ((q = (char **)malloc(SIZEOF(safe_env_list))) != NULL) {
421 for (p = safe_env_list; *p != NULL; p++) {
422 if ((v = getenv(*p)) == NULL) {
423 continue; /* no variable to dup */
425 l1 = strlen(*p); /* variable name w/o null */
426 l2 = strlen(v) + 1; /* include null byte here */
427 if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
428 break; /* out of memory */
430 *q++ = s; /* save the new pointer */
431 memcpy(s, *p, l1); /* left hand side */
434 memcpy(s, v, l2); /* right hand side and null */
436 *q = NULL; /* terminate the list */
442 * amtable_alloc -- (re)allocate enough space for some number of elements.
444 * input: table -- pointer to pointer to table
445 * current -- pointer to current number of elements
446 * elsize -- size of a table element
447 * count -- desired number of elements
448 * bump -- round up factor
449 * init_func -- optional element initialization function
450 * output: table -- possibly adjusted to point to new table area
451 * current -- possibly adjusted to new number of elements
463 void (*init_func)(void *))
466 size_t table_count_new;
469 if (count >= *current) {
470 table_count_new = ((count + bump) / bump) * bump;
471 table_new = debug_alloc(s, l, table_count_new * elsize);
473 memcpy(table_new, *table, *current * elsize);
477 memset(((char *)*table) + *current * elsize,
479 (table_count_new - *current) * elsize);
480 if (init_func != NULL) {
481 for (i = *current; i < table_count_new; i++) {
482 (*init_func)(((char *)*table) + i * elsize);
485 *current = table_count_new;
491 * amtable_free -- release a table.
493 * input: table -- pointer to pointer to table
494 * current -- pointer to current number of elements
495 * output: table -- possibly adjusted to point to new table area
496 * current -- possibly adjusted to new number of elements