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 <dvlasenk@redhat.com>
diff --git a/count.c b/count.c
index 77fc919..1785242 100644
--- a/count.c
+++ b/count.c
@@ -55,11 +55,8 @@
 
 	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 @@
 	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 dfca2c1..bb2e395 100644
--- a/defs.h
+++ b/defs.h
@@ -580,6 +580,7 @@
 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 a8dbe95..e77a238 100644
--- a/desc.c
+++ b/desc.c
@@ -497,9 +497,9 @@
 	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 @@
 				tprintf(", NULL");
 				continue;
 			}
-			if (fds == NULL || !verbose(tcp)) {
+			if (!verbose(tcp)) {
 				tprintf(", %#lx", arg);
 				continue;
 			}
@@ -546,8 +546,8 @@
 		}
 
 		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 @@
 			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 c40fde2..09977e9 100644
--- a/file.c
+++ b/file.c
@@ -2422,11 +2422,8 @@
 	}
 	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 @@
 	}
 	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 @@
 	}
 	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 763bea1..43b422f 100644
--- a/mem.c
+++ b/mem.c
@@ -564,12 +564,12 @@
 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 @@
 			}
 			tprintf("]");
 		}
-		if (vec)
-			free(vec);
+		free(vec);
 	}
 	return 0;
 }
diff --git a/pathtrace.c b/pathtrace.c
index 3ebb427..23ab47e 100644
--- a/pathtrace.c
+++ b/pathtrace.c
@@ -290,10 +290,8 @@
 			  & -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 bb41ce2..83ebc5b 100644
--- a/strace.c
+++ b/strace.c
@@ -264,6 +264,15 @@
 	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 @@
 	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 @@
 	/* 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 @@
 			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 @@
 
 	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 @@
 	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 @@
 
 	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 f8c4c8b..b21ce01 100644
--- a/syscall.c
+++ b/syscall.c
@@ -473,10 +473,8 @@
 		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 7bf2698..75a449d 100644
--- a/util.c
+++ b/util.c
@@ -619,14 +619,15 @@
 		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 @@
 	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 @@
 {
 	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 @@
 		return;
 
 	for (i = 0; i < len; i += 16) {
+		char outstr[80];
+
 		s = outstr;
 		sprintf(s, " | %05x ", i);
 		s += 9;
@@ -1741,10 +1739,8 @@
 		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;