[PATCH] Introduce xmalloc, memory allocator with die_out_of_memory()

Masatake YAMATO yamato at redhat.com
Mon Apr 6 15:40:35 UTC 2015


In strace following code sentences are frequently used:

   var = malloc(fdsize);
    if (!var)
       die_out_of_memory();

This patch introduces xmalloc and friends which simplify
above sentences like:

   var = xmalloc(fdsize);

Here friends are xcalloc and xreallocarray.
Some part of xreallocarray is derived from reallocarray which
is developed at OpenBSD project as a safer alternative of
realloc.

* defs.h: (xmalloc, xcalloc, xreallocarray): New declarations.
* xmalloc.c (xmalloc, xcalloc, xreallocarray): New file with new functions.
* vsprintf.c (strace_vfprintf): Use xmalloc.
* util.c (printstr): Use xmalloc.
* unwind.c (unwind_tcb_init): Use xmalloc.
(build_mmap_cache): Use xmalloc and xreallocarray.
(get_symbol_name): Use xreallocarray.
* syscall.c (reallocate_qual): Use xreallocarray.
* strace.c (expand_tcbtab): Use xcalloc and xreallocarray.
(init): Use xcalloc and xmalloc.
* pathtrace.c (storepath): Use xreallocarray.
(pathtrace_match): Use xmalloc.
* dirent.c (sys_getdents): Use xmalloc.
(sys_getdents64): Use xmalloc.
* desc.c (decode_select): Use xmalloc.
* count.c (count_syscall): Use xcalloc.
(call_summary_pers): Use xcalloc.
---
 Makefile.am |  3 +-
 count.c     | 11 ++------
 defs.h      |  9 ++++++
 desc.c      | 11 ++------
 dirent.c    |  8 ++----
 pathtrace.c |  8 ++----
 strace.c    | 22 ++++-----------
 syscall.c   |  4 +--
 unwind.c    | 26 +++++------------
 util.c      |  8 ++----
 vsprintf.c  |  4 +--
 xmalloc.c   | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 12 files changed, 130 insertions(+), 76 deletions(-)
 create mode 100644 xmalloc.c

diff --git a/Makefile.am b/Makefile.am
index 8193c9e..b44b7a2 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 25921b2..1232d3d 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 34f1603..a52126c 100644
--- a/defs.h
+++ b/defs.h
@@ -434,6 +434,15 @@ void perror_msg_and_die(const char *fmt, ...)
 	ATTRIBUTE_FORMAT((printf, 1, 2)) ATTRIBUTE_NORETURN;
 void die_out_of_memory(void) ATTRIBUTE_NORETURN;
 
+/*
+ * Memory allocator + die_out_of_memory
+ */
+void *xmalloc(size_t size) ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE((1));
+void *xcalloc(size_t nmmeb, size_t size)
+	ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE((1, 2));
+void *xreallocarray(void *optr, size_t nmemb, size_t size)
+	ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE((1, 2));
+
 #if USE_CUSTOM_PRINTF
 /*
  * See comment in vsprintf.c for allowed formats.
diff --git a/desc.c b/desc.c
index 485c802..1c10d9f 100644
--- a/desc.c
+++ b/desc.c
@@ -338,11 +338,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) {
@@ -387,9 +384,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 d30e0d2..2b6acb6 100644
--- a/dirent.c
+++ b/dirent.c
@@ -83,9 +83,7 @@ sys_getdents(struct tcb *tcp)
 		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);
@@ -167,9 +165,7 @@ sys_getdents64(struct tcb *tcp)
 		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/pathtrace.c b/pathtrace.c
index 0db7fe3..b8da572 100644
--- a/pathtrace.c
+++ b/pathtrace.c
@@ -91,9 +91,7 @@ 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 +285,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 5eab360..84a1334 100644
--- a/strace.c
+++ b/strace.c
@@ -676,10 +676,8 @@ 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)
@@ -1445,12 +1443,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++;
 
@@ -1596,9 +1590,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 +1683,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 d54d8b6..bfaee9f 100644
--- a/syscall.c
+++ b/syscall.c
@@ -381,9 +381,7 @@ 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;
diff --git a/unwind.c b/unwind.c
index 6f422a1..f31c619 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,10 +193,8 @@ 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];
@@ -291,9 +285,7 @@ get_symbol_name(unw_cursor_t *cursor, char **name,
 			break;
 		}
 		*size *= 2;
-		*name = realloc(*name, *size);
-		if (!*name)
-			die_out_of_memory();
+		*name = xreallocarray(*name, *size, 1);
 	}
 }
 
@@ -372,9 +364,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,9 +480,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,
diff --git a/util.c b/util.c
index 6afafbb..9dad3f1 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 0125e72..aae40db 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 0000000..a34223d
--- /dev/null
+++ b/xmalloc.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1991, 1992 Paul Kranenburg <pk at cs.few.eur.nl>
+ * Copyright (c) 1993 Branko Lankester <branko at hacktic.nl>
+ * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs at world.std.com>
+ * Copyright (c) 1996-1999 Wichert Akkerman <wichert at cistron.nl>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+
+void *
+xmalloc(size_t size)
+{
+	void *r = malloc(size);
+	if (!r)
+		die_out_of_memory();
+	return r;
+}
+
+void *
+xcalloc(size_t nmmeb, size_t size)
+{
+	void *r = calloc(nmmeb, size);
+	if (!r)
+		die_out_of_memory();
+	return r;
+}
+
+/* (part of xreallocarray is derived from reallocarray)
+ *
+ * About reallocarray
+ *
+ * Copyright (c) 2008 Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+xreallocarray(void *optr, size_t nmemb, size_t size)
+{
+	void *r;
+	size_t bytes = nmemb * size;
+
+	if (((nmemb | size) >= MUL_NO_OVERFLOW) &&
+	    size && bytes / size != nmemb)
+		die_out_of_memory();
+
+
+	r = realloc(optr, size * nmemb);
+	if (!r)
+		die_out_of_memory();
+
+	return r;
+}
-- 
2.1.0





More information about the Strace-devel mailing list