From: Denys Vlasenko Date: Wed, 31 Aug 2011 12:00:02 +0000 (+0200) Subject: Make out-of-memory handling more uniform X-Git-Tag: v4.7~271 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1d46ba57a8ab16b353b531f2bbefe2ad7f354ca9;p=strace Make out-of-memory handling more uniform This fixes one real bug in dumpstr(). * defs.h: Declare die_out_of_memory(). * strace.c (die_out_of_memory): New function. (strace_popen): If allocation fails, call die_out_of_memory(). (main): Likewise. (expand_tcbtab): Likewise. (rebuild_pollv): Likewise. * count.c (count_syscall): Likewise. (call_summary_pers): Likewise. * desc.c (decode_select): Likewise. * file.c (sys_getdents): Likewise. (sys_getdents64): Likewise. (sys_getdirentries): Likewise. * pathtrace.c (pathtrace_match): Likewise. * syscall.c (qualify): Likewise. * util.c (printstr): Likewise. (dumpiov): Likewise. (dumpstr): Likewise. (fixvfork): Likewise. * mem.c (sys_mincore): Don't check free() parameter for NULL. Signed-off-by: Denys Vlasenko --- diff --git a/count.c b/count.c index 77fc919d..1785242a 100644 --- a/count.c +++ b/count.c @@ -55,11 +55,8 @@ count_syscall(struct tcb *tcp, struct timeval *tv) if (!counts) { counts = calloc(nsyscalls, sizeof(*counts)); - if (!counts) { - fprintf(stderr, - "strace: out of memory for call counts\n"); - exit(1); - } + if (!counts) + die_out_of_memory(); } counts[tcp->scno].calls++; @@ -157,10 +154,8 @@ call_summary_pers(FILE *outf) char error_str[16]; int *sorted_count = calloc(sizeof(int), nsyscalls); - if (!sorted_count) { - fprintf(stderr, "strace: out of memory for call summary\n"); - return; - } + if (!sorted_count) + die_out_of_memory(); call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0; if (overhead.tv_sec == -1) { diff --git a/defs.h b/defs.h index dfca2c12..bb2e395d 100644 --- a/defs.h +++ b/defs.h @@ -580,6 +580,7 @@ void error_msg(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); void perror_msg(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); void error_msg_and_die(const char *fmt, ...) __attribute__ ((noreturn, format(printf, 1, 2))); void perror_msg_and_die(const char *fmt, ...) __attribute__ ((noreturn, format(printf, 1, 2))); +void die_out_of_memory(void) __attribute__ ((noreturn)); extern void set_personality(int personality); extern const char *xlookup(const struct xlat *, int); diff --git a/desc.c b/desc.c index a8dbe955..e77a2387 100644 --- a/desc.c +++ b/desc.c @@ -497,9 +497,9 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) long arg; if (entering(tcp)) { - fds = (fd_set *) malloc(fdsize); - if (fds == NULL) - fprintf(stderr, "out of memory\n"); + fds = malloc(fdsize); + if (!fds) + die_out_of_memory(); nfds = args[0]; tprintf("%d", nfds); for (i = 0; i < 3; i++) { @@ -508,7 +508,7 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) tprintf(", NULL"); continue; } - if (fds == NULL || !verbose(tcp)) { + if (!verbose(tcp)) { tprintf(", %#lx", arg); continue; } @@ -546,8 +546,8 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) } fds = malloc(fdsize); - if (fds == NULL) - fprintf(stderr, "out of memory\n"); + if (!fds) + die_out_of_memory(); tcp->auxstr = outstr; outptr = outstr; @@ -556,8 +556,7 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) int first = 1; arg = args[i+1]; - if (fds == NULL || !arg || - umoven(tcp, arg, fdsize, (char *) fds) < 0) + if (!arg || umoven(tcp, arg, fdsize, (char *) fds) < 0) continue; for (j = 0; j < args[0]; j++) { if (FD_ISSET(j, fds)) { diff --git a/file.c b/file.c index c40fde2b..09977e9c 100644 --- a/file.c +++ b/file.c @@ -2422,11 +2422,8 @@ sys_getdents(struct tcb *tcp) } len = tcp->u_rval; buf = len ? malloc(len) : NULL; - if (len && !buf) { - tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); - fprintf(stderr, "out of memory\n"); - return 0; - } + if (len && !buf) + die_out_of_memory(); if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) { tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); free(buf); @@ -2507,11 +2504,8 @@ sys_getdents64(struct tcb *tcp) } len = tcp->u_rval; buf = len ? malloc(len) : NULL; - if (len && !buf) { - tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); - fprintf(stderr, "out of memory\n"); - return 0; - } + if (len && !buf) + die_out_of_memory(); if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) { tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); free(buf); @@ -2581,11 +2575,8 @@ sys_getdirentries(struct tcb *tcp) } len = tcp->u_rval; buf = malloc(len); - if (buf == NULL) { - tprintf("%#lx, %lu, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]); - fprintf(stderr, "out of memory\n"); - return 0; - } + if (!buf) + die_out_of_memory(); if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) { tprintf("%#lx, %lu, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]); free(buf); diff --git a/mem.c b/mem.c index 763bea16..43b422f5 100644 --- a/mem.c +++ b/mem.c @@ -564,12 +564,12 @@ sys_mctl(struct tcb *tcp) int sys_mincore(struct tcb *tcp) { - unsigned long i, len; - char *vec = NULL; - if (entering(tcp)) { tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]); } else { + unsigned long i, len; + char *vec = NULL; + len = tcp->u_arg[1]; if (syserror(tcp) || tcp->u_arg[2] == 0 || (vec = malloc(len)) == NULL || @@ -586,8 +586,7 @@ sys_mincore(struct tcb *tcp) } tprintf("]"); } - if (vec) - free(vec); + free(vec); } return 0; } diff --git a/pathtrace.c b/pathtrace.c index 3ebb427e..23ab47ee 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -290,10 +290,8 @@ pathtrace_match(struct tcb *tcp) & -sizeof(long)); fds = malloc(fdsize); - if (fds == NULL) { - fprintf(stderr, "out of memory\n"); - return 0; - } + if (!fds) + die_out_of_memory(); for (i = 1; i <= 3; ++i) { if (args[i] == 0) diff --git a/strace.c b/strace.c index bb41ce2b..83ebc5b0 100644 --- a/strace.c +++ b/strace.c @@ -264,6 +264,15 @@ 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"); +} + #ifdef SVR4 #ifdef MIPS void @@ -383,7 +392,7 @@ strace_popen(const char *command) swap_uid(); fp = fdopen(fds[1], "w"); if (!fp) - error_msg_and_die("Out of memory"); + die_out_of_memory(); return fp; } @@ -947,11 +956,11 @@ main(int argc, char *argv[]) /* Allocate the initial tcbtab. */ tcbtabsize = argc; /* Surely enough for all -p args. */ tcbtab = calloc(tcbtabsize, sizeof(tcbtab[0])); - if (tcbtab == NULL) - error_msg_and_die("Out of memory"); + if (!tcbtab) + die_out_of_memory(); tcp = calloc(tcbtabsize, sizeof(*tcp)); - if (tcp == NULL) - error_msg_and_die("Out of memory"); + if (!tcp) + die_out_of_memory(); for (c = 0; c < tcbtabsize; c++) tcbtab[c] = tcp++; @@ -1078,9 +1087,8 @@ main(int argc, char *argv[]) username = strdup(optarg); break; case 'E': - if (putenv(optarg) < 0) { - error_msg_and_die("Out of memory"); - } + if (putenv(optarg) < 0) + die_out_of_memory(); break; default: usage(stderr, 1); @@ -1090,7 +1098,7 @@ main(int argc, char *argv[]) acolumn_spaces = malloc(acolumn + 1); if (!acolumn_spaces) - error_msg_and_die("Out of memory"); + die_out_of_memory(); memset(acolumn_spaces, ' ', acolumn); acolumn_spaces[acolumn] = '\0'; @@ -1240,8 +1248,8 @@ expand_tcbtab(void) int i = tcbtabsize; struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0])); struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0])); - if (newtab == NULL || newtcbs == NULL) - error_msg_and_die("Out of memory"); + if (!newtab || !newtcbs) + die_out_of_memory(); tcbtabsize *= 2; tcbtab = newtab; while (i < tcbtabsize) @@ -1866,9 +1874,8 @@ rebuild_pollv(void) free(pollv); pollv = malloc(nprocs * sizeof(pollv[0])); - if (pollv == NULL) { - error_msg_and_die("Out of memory"); - } + if (!pollv) + die_out_of_memory(); for (i = j = 0; i < tcbtabsize; i++) { struct tcb *tcp = tcbtab[i]; diff --git a/syscall.c b/syscall.c index f8c4c8ba..b21ce019 100644 --- a/syscall.c +++ b/syscall.c @@ -473,10 +473,8 @@ qualify(const char *s) qualify_one(i, opt->bitflag, !not, -1); } copy = strdup(s); - if (!copy) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + if (!copy) + die_out_of_memory(); for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) { if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) { for (i = 0; i < nsyscalls0; i++) diff --git a/util.c b/util.c index 7bf26984..75a449dc 100644 --- a/util.c +++ b/util.c @@ -619,14 +619,15 @@ printstr(struct tcb *tcp, long addr, int len) return; } /* Allocate static buffers if they are not allocated yet. */ - if (!str) + if (!str) { str = malloc(max_strlen + 1); - if (!outstr) + if (!str) + die_out_of_memory(); + } + if (!outstr) { outstr = malloc(4 * max_strlen + sizeof "\"...\""); - if (!str || !outstr) { - fprintf(stderr, "out of memory\n"); - tprintf("%#lx", addr); - return; + if (!outstr) + die_out_of_memory(); } if (len < 0) { @@ -687,10 +688,9 @@ dumpiov(struct tcb *tcp, int len, long addr) unsigned long size; size = sizeof_iov * (unsigned long) len; - if (size / sizeof_iov != len + if (size / sizeof_iov != len /* overflow? */ || (iov = malloc(size)) == NULL) { - fprintf(stderr, "out of memory\n"); - return; + die_out_of_memory(); } if (umoven(tcp, addr, size, (char *) iov) >= 0) { for (i = 0; i < len; i++) { @@ -715,18 +715,14 @@ dumpstr(struct tcb *tcp, long addr, int len) { static int strsize = -1; static unsigned char *str; - static char outstr[80]; char *s; int i, j; if (strsize < len) { free(str); str = malloc(len); - if (str == NULL) { - fprintf(stderr, "out of memory\n"); - /* BUG! On next call we may use NULL str! */ - return; - } + if (!str) + die_out_of_memory(); strsize = len; } @@ -734,6 +730,8 @@ dumpstr(struct tcb *tcp, long addr, int len) return; for (i = 0; i < len; i += 16) { + char outstr[80]; + s = outstr; sprintf(s, " | %05x ", i); s += 9; @@ -1741,10 +1739,8 @@ fixvfork(struct tcb *tcp) return -1; } strtab = malloc((unsigned)ld.ld_symb_size); - if (strtab == NULL) { - fprintf(stderr, "out of memory\n"); - return -1; - } + if (!strtab) + die_out_of_memory(); if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr), (int)ld.ld_symb_size, strtab) < 0) goto err;