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
38 static char *internal_vstralloc(const char *, va_list);
41 *=====================================================================
42 * debug_caller_loc -- keep track of all allocation callers
44 * const char *debug_caller_loc(const char *file, int line)
46 * entry: file = source file
48 * exit: a string like "genversion.c@999"
50 * The debug malloc library has a concept of a call stack that can be used
51 * to fine tune what was running when a particular allocation was done.
52 * We use it to tell who called our various allocation wrappers since
53 * it wouldn't do much good to tell us a problem happened because of
54 * the malloc call in alloc (they are all from there at some point).
56 * But the library expects the string passed to malloc_enter/malloc_leave
57 * to be static, so we build a linked list of each one we get (there are
58 * not really that many during a given execution). When we get a repeat
59 * we return the previously allocated string. For a bit of performance,
60 * we keep the list in least recently used order, which helps because
61 * the calls to us come in pairs (one for malloc_enter and one right
62 * after for malloc_leave).
63 *=====================================================================
74 LIST_ENTRY(loc_str) le;
76 static LIST_HEAD(, loc_str) root = LIST_HEAD_INITIALIZER(root);
77 static char loc[256]; /* big enough for filename@lineno */
80 if ((p = strrchr(file, '/')) != NULL)
81 file = p + 1; /* just the last path element */
83 snprintf(loc, SIZEOF(loc), "%s@%d", file, line);
85 for (ls = LIST_FIRST(&root); ls != NULL; ls = LIST_NEXT(ls, le)) {
86 if (strcmp(loc, ls->str) == 0) {
87 if (ls != LIST_FIRST(&root)) {
89 * This is a repeat and was not at the head of the list.
90 * Unlink it and move it to the front.
93 LIST_INSERT_HEAD(&root, ls, le);
100 * This is a new entry. Put it at the head of the list.
102 ls = malloc(SIZEOF(*ls));
104 return ("??"); /* not much better than abort */
105 ls->str = malloc(strlen(loc) + 1);
106 if (ls->str == NULL) {
108 return ("??"); /* not much better than abort */
110 strcpy(ls->str, loc);
112 malloc_mark(ls->str);
113 LIST_INSERT_HEAD(&root, ls, le);
118 *=====================================================================
119 * Save the current source line for vstralloc/newvstralloc.
121 * int debug_alloc_push (char *s, int l)
123 * entry: s = source file
127 * See the comments in amanda.h about what this is used for.
128 *=====================================================================
131 #define DEBUG_ALLOC_SAVE_MAX 10
136 } debug_alloc_loc_info[DEBUG_ALLOC_SAVE_MAX];
137 static int debug_alloc_ptr = 0;
139 static char *saved_file;
140 static int saved_line;
147 debug_alloc_loc_info[debug_alloc_ptr].file = s;
148 debug_alloc_loc_info[debug_alloc_ptr].line = l;
149 debug_alloc_ptr = (debug_alloc_ptr + 1) % DEBUG_ALLOC_SAVE_MAX;
154 *=====================================================================
155 * Pop the current source line information for vstralloc/newvstralloc.
157 * int debug_alloc_pop (void)
162 * See the comments in amanda.h about what this is used for.
163 *=====================================================================
167 debug_alloc_pop(void)
170 (debug_alloc_ptr + DEBUG_ALLOC_SAVE_MAX - 1) % DEBUG_ALLOC_SAVE_MAX;
171 saved_file = debug_alloc_loc_info[debug_alloc_ptr].file;
172 saved_line = debug_alloc_loc_info[debug_alloc_ptr].line;
176 * alloc - a wrapper for malloc.
186 malloc_enter(debug_caller_loc(s, l));
187 addr = (void *)malloc(max(size, 1));
189 errordump("%s@%d: memory allocation failed (" SIZE_T_FMT " bytes requested)",
192 (SIZE_T_FMT_TYPE)size);
195 malloc_leave(debug_caller_loc(s, l));
201 * newalloc - free existing buffer and then alloc a new one.
212 malloc_enter(debug_caller_loc(s, l));
213 addr = debug_alloc(s, l, size);
215 malloc_leave(debug_caller_loc(s, l));
221 * stralloc - copies the given string into newly allocated memory.
222 * Just like strdup()!
232 malloc_enter(debug_caller_loc(s, l));
233 addr = debug_alloc(s, l, strlen(str) + 1);
235 malloc_leave(debug_caller_loc(s, l));
239 /* vstrextend -- Extends the existing string by appending the other
246 char *keep = *oldstr;
249 arglist_start(ap, oldstr);
253 *oldstr = internal_vstralloc(*oldstr, ap);
262 * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
265 * The MAX_STR_ARGS limit is purely an efficiency issue so we do not have
266 * to scan the strings more than necessary.
269 #define MAX_VSTRALLOC_ARGS 32
280 const char *arg[MAX_VSTRALLOC_ARGS+1];
281 size_t len[MAX_VSTRALLOC_ARGS+1];
285 errordump("internal_vstralloc: str is NULL");
292 total_len = len[a] = l;
295 while ((next = arglist_val(argp, char *)) != NULL) {
296 if ((l = strlen(next)) == 0) {
297 continue; /* minor optimisation */
299 if (a >= MAX_VSTRALLOC_ARGS) {
300 errordump("%s@%d: more than %d args to vstralloc",
301 saved_file ? saved_file : "(unknown)",
302 saved_file ? saved_line : -1,
312 result = debug_alloc(saved_file, saved_line, total_len+1);
315 for (b = 0; b < a; b++) {
316 memcpy(next, arg[b], len[b]);
326 * vstralloc - copies multiple strings into newly allocated memory.
329 char *debug_vstralloc,
336 malloc_enter(debug_caller_loc(saved_file, saved_line));
337 arglist_start(argp, str);
338 result = internal_vstralloc(str, argp);
340 malloc_leave(debug_caller_loc(saved_file, saved_line));
346 * newstralloc - free existing string and then stralloc a new one.
357 malloc_enter(debug_caller_loc(s, l));
358 addr = debug_stralloc(s, l, newstr);
360 malloc_leave(debug_caller_loc(s, l));
366 * newvstralloc - free existing string and then vstralloc a new one.
369 char *debug_newvstralloc,
371 const char *, newstr)
377 malloc_enter(debug_caller_loc(saved_file, saved_line));
378 arglist_start(argp, newstr);
379 result = internal_vstralloc(newstr, argp);
382 malloc_leave(debug_caller_loc(saved_file, saved_line));
388 * vstrallocf - copies printf formatted string into newly allocated memory.
400 malloc_enter(debug_caller_loc(saved_file, saved_line));
402 result = debug_alloc(saved_file, saved_line, MIN_ALLOC);
403 if (result != NULL) {
405 arglist_start(argp, fmt);
406 size = vsnprintf(result, MIN_ALLOC, fmt, argp);
409 if (size >= (size_t)MIN_ALLOC) {
411 result = debug_alloc(saved_file, saved_line, size + 1);
413 arglist_start(argp, fmt);
414 (void)vsnprintf(result, size + 1, fmt, argp);
419 malloc_leave(debug_caller_loc(saved_file, saved_line));
423 extern char **environ;
425 * safe_env - build a "safe" environment list.
430 static char *safe_env_list[] = {
443 * If the initial environment pointer malloc fails, set up to
444 * pass back a pointer to the NULL string pointer at the end of
445 * safe_env_list so our result is always a valid, although possibly
446 * empty, environment list.
448 #define SAFE_ENV_CNT (size_t)(sizeof(safe_env_list) / sizeof(*safe_env_list))
449 char **envp = safe_env_list + SAFE_ENV_CNT - 1;
459 if (getuid() == geteuid() && getgid() == getegid()) {
461 for (env = environ; *env != NULL; env++)
463 if ((q = (char **)malloc(env_cnt*SIZEOF(char *))) != NULL) {
466 for (env = environ; *env != NULL; env++) {
467 if (strncmp("LANG=", *env, 5) != 0 &&
468 strncmp("LC_", *env, 3) != 0) {
478 if ((q = (char **)malloc(SIZEOF(safe_env_list))) != NULL) {
480 for (p = safe_env_list; *p != NULL; p++) {
481 if ((v = getenv(*p)) == NULL) {
482 continue; /* no variable to dup */
484 l1 = strlen(*p); /* variable name w/o null */
485 l2 = strlen(v) + 1; /* include null byte here */
486 if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
487 break; /* out of memory */
489 *q++ = s; /* save the new pointer */
490 memcpy(s, *p, l1); /* left hand side */
493 memcpy(s, v, l2); /* right hand side and null */
495 *q = NULL; /* terminate the list */
501 * amtable_alloc -- (re)allocate enough space for some number of elements.
503 * input: table -- pointer to pointer to table
504 * current -- pointer to current number of elements
505 * elsize -- size of a table element
506 * count -- desired number of elements
507 * bump -- round up factor
508 * init_func -- optional element initialization function
509 * output: table -- possibly adjusted to point to new table area
510 * current -- possibly adjusted to new number of elements
522 void (*init_func)(void *))
525 size_t table_count_new;
528 if (count >= *current) {
529 table_count_new = ((count + bump) / bump) * bump;
530 table_new = debug_alloc(s, l, table_count_new * elsize);
532 memcpy(table_new, *table, *current * elsize);
536 memset(((char *)*table) + *current * elsize,
538 (table_count_new - *current) * elsize);
539 if (init_func != NULL) {
540 for (i = *current; i < table_count_new; i++) {
541 (*init_func)(((char *)*table) + i * elsize);
544 *current = table_count_new;
550 * amtable_free -- release a table.
552 * input: table -- pointer to pointer to table
553 * current -- pointer to current number of elements
554 * output: table -- possibly adjusted to point to new table area
555 * current -- possibly adjusted to new number of elements