diff --git a/Makefile.am b/Makefile.am index d4be76f6..e2a0f747 100644 --- a/Makefile.am +++ b/Makefile.am @@ -123,7 +123,8 @@ strace_SOURCES = \ v4l2.c \ vsprintf.c \ wait.c \ - xattr.c + xattr.c \ + xmalloc.c if USE_LIBUNWIND strace_SOURCES += unwind.c diff --git a/count.c b/count.c index 25921b25..1232d3db 100644 --- a/count.c +++ b/count.c @@ -58,11 +58,8 @@ count_syscall(struct tcb *tcp, const struct timeval *syscall_exiting_tv) if (!SCNO_IN_RANGE(scno)) return; - if (!counts) { - counts = calloc(nsyscalls, sizeof(*counts)); - if (!counts) - die_out_of_memory(); - } + if (!counts) + counts = xcalloc(nsyscalls, sizeof(*counts)); cc = &counts[scno]; cc->calls++; @@ -171,9 +168,7 @@ call_summary_pers(FILE *outf) fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n", dashes, dashes, dashes, dashes, dashes, dashes); - sorted_count = calloc(sizeof(int), nsyscalls); - if (!sorted_count) - die_out_of_memory(); + sorted_count = xcalloc(sizeof(int), nsyscalls); call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0; if (overhead.tv_sec == -1) { tv_mul(&overhead, &shortest, 8); diff --git a/defs.h b/defs.h index 77c819c6..c02f8103 100644 --- a/defs.h +++ b/defs.h @@ -434,6 +434,13 @@ void perror_msg_and_die(const char *fmt, ...) ATTRIBUTE_FORMAT((printf, 1, 2)) ATTRIBUTE_NORETURN; void die_out_of_memory(void) ATTRIBUTE_NORETURN; +void *xmalloc(size_t size) ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE((1)); +void *xcalloc(size_t nmemb, size_t size) + ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE((1, 2)); +void *xreallocarray(void *ptr, size_t nmemb, size_t size) + ATTRIBUTE_ALLOC_SIZE((2, 3)); +char *xstrdup(const char *str) ATTRIBUTE_MALLOC; + #if USE_CUSTOM_PRINTF /* * See comment in vsprintf.c for allowed formats. diff --git a/desc.c b/desc.c index 1b9dd1a5..e1d01dc4 100644 --- a/desc.c +++ b/desc.c @@ -331,11 +331,8 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) if (entering(tcp)) { tprintf("%d", (int) args[0]); - if (verbose(tcp) && fdsize > 0) { - fds = malloc(fdsize); - if (!fds) - die_out_of_memory(); - } + if (verbose(tcp) && fdsize > 0) + fds = xmalloc(fdsize); for (i = 0; i < 3; i++) { arg = args[i+1]; if (arg == 0) { @@ -380,9 +377,7 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) return RVAL_STR; } - fds = malloc(fdsize); - if (!fds) - die_out_of_memory(); + fds = xmalloc(fdsize); outptr = outstr; sep = ""; diff --git a/dirent.c b/dirent.c index 32f04b9e..988d535c 100644 --- a/dirent.c +++ b/dirent.c @@ -81,9 +81,7 @@ SYS_FUNC(getdents) len = tcp->u_rval; if (len) { - buf = malloc(len); - if (!buf) - die_out_of_memory(); + buf = xmalloc(len); if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) { tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); free(buf); @@ -164,9 +162,7 @@ SYS_FUNC(getdents64) len = tcp->u_rval; if (len) { - buf = malloc(len); - if (!buf) - die_out_of_memory(); + buf = xmalloc(len); if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) { tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); free(buf); diff --git a/net.c b/net.c index 2ed950de..0a3c601f 100644 --- a/net.c +++ b/net.c @@ -995,7 +995,7 @@ SYS_FUNC(recvmmsg) /* Abusing tcp->auxstr as temp storage. * Will be used and freed on syscall exit. */ - tcp->auxstr = strdup(str); + tcp->auxstr = xstrdup(str); } else { tprintf("%#lx, %ld, ", tcp->u_arg[1], tcp->u_arg[2]); printflags(msg_flags, tcp->u_arg[3], "MSG_???"); diff --git a/pathtrace.c b/pathtrace.c index 0db7fe31..894dd5c9 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -91,9 +91,8 @@ storepath(const char *path) return; /* already in table */ i = num_selected++; - paths_selected = realloc(paths_selected, num_selected * sizeof(paths_selected[0])); - if (!paths_selected) - die_out_of_memory(); + paths_selected = xreallocarray(paths_selected, num_selected, + sizeof(paths_selected[0])); paths_selected[i] = path; } @@ -287,9 +286,7 @@ pathtrace_match(struct tcb *tcp) if (nfds > 1024*1024) nfds = 1024*1024; fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize; - fds = malloc(fdsize); - if (!fds) - die_out_of_memory(); + fds = xmalloc(fdsize); for (i = 1; i <= 3; ++i) { if (args[i] == 0) diff --git a/strace.c b/strace.c index 5eab3603..0bffd5e1 100644 --- a/strace.c +++ b/strace.c @@ -324,15 +324,6 @@ void perror_msg_and_die(const char *fmt, ...) die(); } -void die_out_of_memory(void) -{ - static bool recursed = 0; - if (recursed) - exit(1); - recursed = 1; - error_msg_and_die("Out of memory"); -} - static void error_opt_arg(int opt, const char *arg) { @@ -676,10 +667,9 @@ expand_tcbtab(void) So tcbtab is a table of pointers. Since we never free the TCBs, we allocate a single chunk of many. */ unsigned int i = tcbtabsize; - struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0])); - struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0])); - if (!newtab || !newtcbs) - die_out_of_memory(); + struct tcb *newtcbs = xcalloc(tcbtabsize, sizeof(newtcbs[0])); + struct tcb **newtab = xreallocarray(tcbtab, tcbtabsize * 2, + sizeof(tcbtab[0])); tcbtabsize *= 2; tcbtab = newtab; while (i < tcbtabsize) @@ -1233,7 +1223,7 @@ startup_child(char **argv) * On NOMMU, can be safely freed only after execve in tracee. * It's hard to know when that happens, so we just leak it. */ - params_for_tracee.pathname = NOMMU_SYSTEM ? strdup(pathname) : pathname; + params_for_tracee.pathname = NOMMU_SYSTEM ? xstrdup(pathname) : pathname; #if defined HAVE_PRCTL && defined PR_SET_PTRACER && defined PR_SET_PTRACER_ANY if (daemonized_tracer) @@ -1445,12 +1435,8 @@ init(int argc, char *argv[]) /* Allocate the initial tcbtab. */ tcbtabsize = argc; /* Surely enough for all -p args. */ - tcbtab = calloc(tcbtabsize, sizeof(tcbtab[0])); - if (!tcbtab) - die_out_of_memory(); - tcp = calloc(tcbtabsize, sizeof(*tcp)); - if (!tcp) - die_out_of_memory(); + tcbtab = xcalloc(tcbtabsize, sizeof(tcbtab[0])); + tcp = xcalloc(tcbtabsize, sizeof(*tcp)); for (tcbi = 0; tcbi < tcbtabsize; tcbi++) tcbtab[tcbi] = tcp++; @@ -1548,7 +1534,7 @@ init(int argc, char *argv[]) qualify(optarg); break; case 'o': - outfname = strdup(optarg); + outfname = xstrdup(optarg); break; case 'O': i = string_to_uint(optarg); @@ -1572,7 +1558,7 @@ init(int argc, char *argv[]) set_sortby(optarg); break; case 'u': - username = strdup(optarg); + username = xstrdup(optarg); break; #ifdef USE_LIBUNWIND case 'k': @@ -1596,9 +1582,7 @@ init(int argc, char *argv[]) argv += optind; /* argc -= optind; - no need, argc is not used below */ - acolumn_spaces = malloc(acolumn + 1); - if (!acolumn_spaces) - die_out_of_memory(); + acolumn_spaces = xmalloc(acolumn + 1); memset(acolumn_spaces, ' ', acolumn); acolumn_spaces[acolumn] = '\0'; @@ -1691,9 +1675,7 @@ init(int argc, char *argv[]) } if (!outfname || outfname[0] == '|' || outfname[0] == '!') { - char *buf = malloc(BUFSIZ); - if (!buf) - die_out_of_memory(); + char *buf = xmalloc(BUFSIZ); setvbuf(shared_log, buf, _IOLBF, BUFSIZ); } if (outfname && argv[0]) { diff --git a/syscall.c b/syscall.c index b63a5280..1a9c5fc2 100644 --- a/syscall.c +++ b/syscall.c @@ -381,9 +381,8 @@ reallocate_qual(const unsigned int n) unsigned p; qualbits_t *qp; for (p = 0; p < SUPPORTED_PERSONALITIES; p++) { - qp = qual_vec[p] = realloc(qual_vec[p], n * sizeof(qualbits_t)); - if (!qp) - die_out_of_memory(); + qp = qual_vec[p] = xreallocarray(qual_vec[p], n, + sizeof(qualbits_t)); memset(&qp[num_quals], 0, (n - num_quals) * sizeof(qualbits_t)); } num_quals = n; @@ -531,9 +530,7 @@ qualify(const char *s) for (i = 0; i < num_quals; i++) { qualify_one(i, opt->bitflag, !not, -1); } - copy = strdup(s); - if (!copy) - die_out_of_memory(); + copy = xstrdup(s); for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) { int n; if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) { diff --git a/unwind.c b/unwind.c index 6f422a1c..7c091f1b 100644 --- a/unwind.c +++ b/unwind.c @@ -107,9 +107,7 @@ unwind_tcb_init(struct tcb *tcp) if (!tcp->libunwind_ui) die_out_of_memory(); - tcp->queue = malloc(sizeof(*tcp->queue)); - if (!tcp->queue) - die_out_of_memory(); + tcp->queue = xmalloc(sizeof(*tcp->queue)); tcp->queue->head = NULL; tcp->queue->tail = NULL; } @@ -152,9 +150,7 @@ build_mmap_cache(struct tcb* tcp) return; } - cache_head = calloc(cur_array_size, sizeof(*cache_head)); - if (!cache_head) - die_out_of_memory(); + cache_head = xcalloc(cur_array_size, sizeof(*cache_head)); while (fgets(buffer, sizeof(buffer), fp) != NULL) { struct mmap_cache_t *entry; @@ -197,19 +193,15 @@ build_mmap_cache(struct tcb* tcp) if (tcp->mmap_cache_size >= cur_array_size) { cur_array_size *= 2; - cache_head = realloc(cache_head, - cur_array_size * sizeof(*cache_head)); - if (!cache_head) - die_out_of_memory(); + cache_head = xreallocarray(cache_head, cur_array_size, + sizeof(*cache_head)); } entry = &cache_head[tcp->mmap_cache_size]; entry->start_addr = start_addr; entry->end_addr = end_addr; entry->mmap_offset = mmap_offset; - entry->binary_filename = strdup(binary_path); - if (!entry->binary_filename) - die_out_of_memory(); + entry->binary_filename = xstrdup(binary_path); tcp->mmap_cache_size++; } fclose(fp); @@ -290,10 +282,8 @@ get_symbol_name(unw_cursor_t *cursor, char **name, *offset = 0; break; } + *name = xreallocarray(*name, 2, *size); *size *= 2; - *name = realloc(*name, *size); - if (!*name) - die_out_of_memory(); } } @@ -372,9 +362,7 @@ stacktrace_walk(struct tcb *tcp, if (tcp->mmap_cache_size == 0) error_msg_and_die("bug: mmap_cache is empty"); - symbol_name = malloc(symbol_name_size); - if (!symbol_name) - die_out_of_memory(); + symbol_name = xmalloc(symbol_name_size); if (unw_init_remote(&cursor, libunwind_as, tcp->libunwind_ui) < 0) perror_msg_and_die("Can't initiate libunwind"); @@ -490,10 +478,7 @@ queue_put(struct queue_t *queue, { struct call_t *call; - call = malloc(sizeof(*call)); - if (!call) - die_out_of_memory(); - + call = xmalloc(sizeof(*call)); call->output_line = sprint_call_or_error(binary_filename, symbol_name, function_offset, diff --git a/util.c b/util.c index 6afafbbf..9dad3f1a 100644 --- a/util.c +++ b/util.c @@ -763,12 +763,8 @@ printstr(struct tcb *tcp, long addr, long len) if (outstr_size / 4 != max_strlen) die_out_of_memory(); - str = malloc(max_strlen + 1); - if (!str) - die_out_of_memory(); - outstr = malloc(outstr_size); - if (!outstr) - die_out_of_memory(); + str = xmalloc(max_strlen + 1); + outstr = xmalloc(outstr_size); } size = max_strlen; diff --git a/vsprintf.c b/vsprintf.c index 0125e720..aae40db3 100644 --- a/vsprintf.c +++ b/vsprintf.c @@ -776,9 +776,7 @@ int strace_vfprintf(FILE *fp, const char *fmt, va_list args) if (len >= buflen) { buflen = len + 256; free(buf); - buf = malloc(buflen); - if (!buf) - die_out_of_memory(); + buf = xmalloc(buflen); /*len =*/ kernel_vsnprintf(buf, buflen, fmt, args); } diff --git a/xmalloc.c b/xmalloc.c new file mode 100644 index 00000000..c852f553 --- /dev/null +++ b/xmalloc.c @@ -0,0 +1,60 @@ +#include "defs.h" + +void die_out_of_memory(void) +{ + static bool recursed = false; + + if (recursed) + exit(1); + recursed = 1; + + error_msg_and_die("Out of memory"); +} + +void *xmalloc(size_t size) +{ + void *p = malloc(size); + + if (!p) + die_out_of_memory(); + + return p; +} + +void *xcalloc(size_t nmemb, size_t size) +{ + void *p = calloc(nmemb, size); + + if (!p) + die_out_of_memory(); + + return p; +} + +#define HALF_SIZE_T (((size_t) 1) << (sizeof(size_t) * 4)) + +void *xreallocarray(void *ptr, size_t nmemb, size_t size) +{ + size_t bytes = nmemb * size; + + if ((nmemb | size) >= HALF_SIZE_T && + size && bytes / size != nmemb) + die_out_of_memory(); + + void *p = realloc(ptr, bytes); + + if (!p) + die_out_of_memory(); + + return p; +} + +char *xstrdup(const char *str) +{ + char *p = strdup(str); + + if (!p) + die_out_of_memory(); + + return p; +}