2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 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.17.2.1.4.3.2.3.2.1 2004/08/31 12:46:06 martinea Exp $
29 * Memory allocators with error handling. If the allocation fails,
30 * errordump() is called, relieving the caller from checking the return
37 *=====================================================================
38 * debug_caller_loc -- keep track of all allocation callers
40 * char *debug_caller_loc(char *file, int line)
42 * entry: file = source file
44 * exit: a string like "genversion.c@999"
46 * The debug malloc library has a concept of a call stack that can be used
47 * to fine tune what was running when a particular allocation was done.
48 * We use it to tell who called our various allocation wrappers since
49 * it wouldn't do much good to tell us a problem happened because of
50 * the malloc call in alloc (they are all from there at some point).
52 * But the library expects the string passed to malloc_enter/malloc_leave
53 * to be static, so we build a linked list of each one we get (there are
54 * not really that many during a given execution). When we get a repeat
55 * we return the previously allocated string. For a bit of performance,
56 * we keep the list in least recently used order, which helps because
57 * the calls to us come in pairs (one for malloc_enter and one right
58 * after for malloc_leave).
59 *=====================================================================
63 debug_caller_loc(file, line)
71 static struct loc_str *root = NULL;
72 struct loc_str *ls, *ls_last;
76 static char *loc = NULL;
77 static int loc_size = 0;
79 if ((p = strrchr(file, '/')) == NULL) {
80 p = file; /* keep the whole name */
82 p++; /* just the last path element */
86 size = len + 1 + NUM_STR_SIZE + 1;
87 if (size > loc_size) {
88 size = ((size + 64 - 1) / 64) * 64; /* might as well get a bunch */
90 * We should free the previous loc area, but we have marked it
91 * as a non-leak and the library considers it an error to free
92 * such an area, so we just ignore it. We probably grabbed
93 * enough the first time that this will not even happen.
97 return "??"; /* not much better than abort */
104 ap_snprintf(loc + len, 1 + NUM_STR_SIZE, "@%d", line);
106 for (ls_last = NULL, ls = root; ls != NULL; ls_last = ls, ls = ls->next) {
107 if (strcmp (loc, ls->str) == 0) {
114 * This is a new entry. Put it at the head of the list.
116 ls = malloc (sizeof (*ls));
118 return "??"; /* not much better than abort */
121 size = strlen (loc) + 1;
122 ls->str = malloc (size);
123 if (ls->str == NULL) {
125 return "??"; /* not much better than abort */
127 malloc_mark (ls->str);
128 strcpy (ls->str, loc);
131 } else if (ls_last != NULL) {
133 * This is a repeat and was not at the head of the list.
134 * Unlink it and move it to the front.
136 ls_last->next = ls->next;
141 * This is a repeat but was already at the head of the list,
142 * so nothing else needs to be done.
149 *=====================================================================
150 * Save the current source line for vstralloc/newvstralloc.
152 * int debug_alloc_push (char *s, int l)
154 * entry: s = source file
158 * See the comments in amanda.h about what this is used for.
159 *=====================================================================
162 #define DEBUG_ALLOC_SAVE_MAX 10
167 } debug_alloc_loc_info[DEBUG_ALLOC_SAVE_MAX];
168 static int debug_alloc_ptr = 0;
170 static char *saved_file;
171 static int saved_line;
174 debug_alloc_push (s, l)
178 debug_alloc_loc_info[debug_alloc_ptr].file = s;
179 debug_alloc_loc_info[debug_alloc_ptr].line = l;
180 debug_alloc_ptr = (debug_alloc_ptr + 1) % DEBUG_ALLOC_SAVE_MAX;
185 *=====================================================================
186 * Pop the current source line information for vstralloc/newvstralloc.
188 * int debug_alloc_pop (void)
193 * See the comments in amanda.h about what this is used for.
194 *=====================================================================
201 (debug_alloc_ptr + DEBUG_ALLOC_SAVE_MAX - 1) % DEBUG_ALLOC_SAVE_MAX;
202 saved_file = debug_alloc_loc_info[debug_alloc_ptr].file;
203 saved_line = debug_alloc_loc_info[debug_alloc_ptr].line;
207 * alloc - a wrapper for malloc.
210 debug_alloc(s, l, size)
217 malloc_enter(debug_caller_loc(s, l));
218 addr = (void *)malloc(max(size, 1));
220 errordump("%s@%d: memory allocation failed (%u bytes requested)",
225 malloc_leave(debug_caller_loc(s, l));
231 * newalloc - free existing buffer and then alloc a new one.
234 debug_newalloc(s, l, old, size)
242 malloc_enter(debug_caller_loc(s, l));
243 addr = debug_alloc(s, l, size);
245 malloc_leave(debug_caller_loc(s, l));
251 * stralloc - copies the given string into newly allocated memory.
252 * Just like strdup()!
255 debug_stralloc(s, l, str)
262 malloc_enter(debug_caller_loc(s, l));
263 addr = debug_alloc(s, l, strlen(str) + 1);
265 malloc_leave(debug_caller_loc(s, l));
271 * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
274 * The MAX_STR_ARGS limit is purely an efficiency issue so we do not have
275 * to scan the strings more than necessary.
278 #define MAX_VSTRALLOC_ARGS 32
281 internal_vstralloc(str, argp)
289 const char *arg[MAX_VSTRALLOC_ARGS+1];
290 size_t len[MAX_VSTRALLOC_ARGS+1];
295 return NULL; /* probably will not happen */
301 total_len = len[a] = l;
304 while ((next = arglist_val(argp, char *)) != NULL) {
305 if ((l = strlen(next)) == 0) {
306 continue; /* minor optimisation */
308 if (a >= MAX_VSTRALLOC_ARGS) {
309 errordump("%s@%d: more than %d arg%s to vstralloc",
310 saved_file ? saved_file : "(unknown)",
311 saved_file ? saved_line : -1,
313 (MAX_VSTRALLOC_ARGS == 1) ? "" : "s");
323 next = result = debug_alloc(saved_file, saved_line, total_len+1);
324 for (a = 0; (s = arg[a]) != NULL; a++) {
325 memcpy(next, s, len[a]);
335 * vstralloc - copies multiple strings into newly allocated memory.
337 arglist_function(char *debug_vstralloc, const char *, str)
343 malloc_enter(debug_caller_loc(saved_file, saved_line));
344 arglist_start(argp, str);
345 result = internal_vstralloc(str, argp);
347 malloc_leave(debug_caller_loc(saved_file, saved_line));
353 * newstralloc - free existing string and then stralloc a new one.
356 debug_newstralloc(s, l, oldstr, newstr)
364 malloc_enter(debug_caller_loc(s, l));
365 addr = debug_stralloc(s, l, newstr);
367 malloc_leave(debug_caller_loc(s, l));
373 * newvstralloc - free existing string and then vstralloc a new one.
375 arglist_function1(char *debug_newvstralloc,
385 malloc_enter(debug_caller_loc(saved_file, saved_line));
386 arglist_start(argp, newstr);
387 result = internal_vstralloc(newstr, argp);
390 malloc_leave(debug_caller_loc(saved_file, saved_line));
396 * sbuf_man - static buffer manager.
398 * Manage a bunch of static buffer pointers.
400 void *sbuf_man(e_bufs, ptr)
401 void *e_bufs; /* XXX - I dont think this is right */
409 /* try and trap bugs */
410 assert(bufs->magic == SBUF_MAGIC);
411 assert(bufs->max > 0);
413 /* initialise first time through */
415 for(slot=0; slot < bufs->max; slot++) {
416 bufs->bufp[slot] = (void *)0;
419 /* calculate the next slot */
420 slot = bufs->cur + 1;
421 if (slot >= bufs->max) slot = 0;
423 /* free the previous inhabitant */
424 if(bufs->bufp[slot] != (void *)0) free(bufs->bufp[slot]);
426 /* store the new one */
427 bufs->bufp[slot] = ptr;
435 * safe_env - build a "safe" environment list.
440 static char *safe_env_list[] = {
452 * If the initial environment pointer malloc fails, set up to
453 * pass back a pointer to the NULL string pointer at the end of
454 * safe_env_list so our result is always a valid, although possibly
455 * empty, environment list.
457 #define SAFE_ENV_CNT (sizeof(safe_env_list) / sizeof(*safe_env_list))
458 char **envp = safe_env_list + SAFE_ENV_CNT - 1;
466 if ((q = (char **)malloc(sizeof(safe_env_list))) != NULL) {
468 for (p = safe_env_list; *p != NULL; p++) {
469 if ((v = getenv(*p)) == NULL) {
470 continue; /* no variable to dup */
472 l1 = strlen(*p); /* variable name w/o null */
473 l2 = strlen(v) + 1; /* include null byte here */
474 if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
475 break; /* out of memory */
477 *q++ = s; /* save the new pointer */
478 memcpy(s, *p, l1); /* left hand side */
481 memcpy(s, v, l2); /* right hand side and null */
483 *q = NULL; /* terminate the list */
489 * amtable_alloc -- (re)allocate enough space for some number of elements.
491 * input: table -- pointer to pointer to table
492 * current -- pointer to current number of elements
493 * elsize -- size of a table element
494 * count -- desired number of elements
495 * bump -- round up factor
496 * init_func -- optional element initialization function
497 * output: table -- possibly adjusted to point to new table area
498 * current -- possibly adjusted to new number of elements
502 debug_amtable_alloc(s, l, table, current, elsize, count, bump, init_func)
510 void (*init_func)(void *);
516 if (count >= *current) {
517 table_count_new = ((count + bump) / bump) * bump;
518 table_new = debug_alloc(s, l, table_count_new * elsize);
520 memcpy(table_new, *table, *current * elsize);
524 memset(((char *)*table) + *current * elsize,
526 (table_count_new - *current) * elsize);
527 if (init_func != NULL) {
528 for (i = *current; i < table_count_new; i++) {
529 (*init_func)(((char *)*table) + i * elsize);
532 *current = table_count_new;
538 * amtable_free -- release a table.
540 * input: table -- pointer to pointer to table
541 * current -- pointer to current number of elements
542 * output: table -- possibly adjusted to point to new table area
543 * current -- possibly adjusted to new number of elements
547 amtable_free(table, current)