2005-05-31  Dmitry V. Levin  <ldv@altlinux.org>

	Deal with memory management issues.
	* defs.h (tprint_iov): Update prototype.
	* desc.c (sys_epoll_wait) [HAVE_SYS_EPOLL_H]: Do not allocate
	epoll_event array of arbitrary size on the stack, to avoid
	stack overflow.
	* file.c (print_xattr_val): Check for integer overflow during
	malloc size calculation, to avoid heap corruption.
	* io.c (tprint_iov) [HAVE_SYS_UIO_H]: Check for integer overflow
	during malloc size calculation, to avoid heap corruption.
	Change iovec array handling to avoid heap memory allocation.
	* mem.c (get_nodes) [LINUX]: Check for integer overflow during
	size calculation and do not allocate array of arbitrary size on
	the stack, to avoid stack overflow.
	* net.c (printcmsghdr) [HAVE_SENDMSG]: Do not allocate array of
	arbitrary size on the stack, to avoid stack overflow.  Do not
	trust cmsg.cmsg_len to avoid read beyond the end of allocated
	object.
	(printmsghdr) [HAVE_SENDMSG]: Update tprint_iov() usage.
	* process.c (sys_setgroups): Check for integer overflow during
	malloc size calculation, to avoid heap corruption.  Change gid_t
	array handling to avoid heap memory allocation.
	(sys_getgroups): Likewise.
	(sys_setgroups32) [LINUX]: Likewise.
	(sys_getgroups32) [LINUX]: Likewise.
	* stream.c (sys_poll) [HAVE_SYS_POLL_H]: Check for integer
	overflow during malloc size calculation, to avoid heap corruption.
	Change pollfd array handling to avoid heap memory allocation.
	* system.c (sys_sysctl) [LINUX]: Check for integer overflow
	during malloc size calculation, to avoid heap corruption.
	* util.c (dumpiov) [HAVE_SYS_UIO_H]: Check for integer overflow
	during malloc size calculation, to avoid heap corruption.
	Fixes RH#159196.
diff --git a/defs.h b/defs.h
index 574a7d2..e32e3ed 100644
--- a/defs.h
+++ b/defs.h
@@ -458,7 +458,7 @@
 extern void tabto P((int));
 extern void call_summary P((FILE *));
 extern void printtv32 P((struct tcb*, long));
-extern void tprint_iov P((struct tcb *, int, long));
+extern void tprint_iov P((struct tcb *, unsigned long, unsigned long));
 
 #ifdef LINUX
 extern int internal_clone P((struct tcb *));
diff --git a/desc.c b/desc.c
index 2432b58..bb30b6f 100644
--- a/desc.c
+++ b/desc.c
@@ -680,20 +680,29 @@
 			tprintf("{}");
 		else {
 #ifdef HAVE_SYS_EPOLL_H
-			struct epoll_event evs[tcp->u_rval];
-			if (umove(tcp, tcp->u_arg[1], evs) == 0) {
-				unsigned long i;
-				tprintf("{");
-				for (i = 0; i < tcp->u_rval; ++i) {
-					if (i > 0)
-						tprintf(", ");
-					print_epoll_event(&evs[i]);
+			struct epoll_event ev, *start, *cur, *end;
+			int failed = 0;
+
+			tprintf("{");
+			start = (struct epoll_event *) tcp->u_arg[1];
+			end = start + tcp->u_rval;
+			for (cur = start; cur < end; ++cur) {
+				if (cur > start)
+					tprintf(", ");
+				if (umove(tcp, (long) cur, &ev) == 0)
+					print_epoll_event(&ev);
+				else {
+					tprintf("?");
+					failed = 1;
+					break;
 				}
-				tprintf("}");
 			}
-			else
+			tprintf("}");
+			if (failed)
+				tprintf(" %#lx", (long) start);
+#else
+			tprintf("{...}");
 #endif
-				tprintf("{...}");
 		}
 		tprintf(", %ld, %ld", tcp->u_arg[2], tcp->u_arg[3]);
 	}
diff --git a/file.c b/file.c
index 821d4a8..52c3631 100644
--- a/file.c
+++ b/file.c
@@ -2347,10 +2347,11 @@
 struct tcb *tcp;
 int failed;
 unsigned long arg;
-long insize, size;
+unsigned long insize, size;
 {
     if (!failed) {
-	unsigned char *buf = malloc(4 * size + 1);
+	unsigned long capacity = 4 * size + 1;
+	unsigned char *buf = (capacity < size) ? NULL : malloc(capacity);
 	if (buf == NULL || /* probably a bogus size argument */
 	    umoven(tcp, arg, size, (char *) &buf[3 * size]) < 0) {
 	    failed = 1;
diff --git a/io.c b/io.c
index 86f9abe..414fbbb 100644
--- a/io.c
+++ b/io.c
@@ -78,38 +78,50 @@
 void
 tprint_iov(tcp, len, addr)
 struct tcb * tcp;
-int len;
-long addr;
+unsigned long len;
+unsigned long addr;
 {
-	struct iovec *iov;
-	int i;
-
+	struct iovec iov;
+	unsigned long size, cur, end, abbrev_end;
+	int failed = 0;
 
 	if (!len) {
 		tprintf("[]");
 		return;
 	}
-
-	if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
-		fprintf(stderr, "No memory");
+	size = len * sizeof(iov);
+	end = addr + size;
+	if (!verbose(tcp) || size / sizeof(iov) != len || end < addr) {
+		tprintf("%#lx", addr);
 		return;
 	}
-	if (umoven(tcp, addr,
-		   len * sizeof *iov, (char *) iov) < 0) {
-		tprintf("%#lx", tcp->u_arg[1]);
+	if (abbrev(tcp)) {
+		abbrev_end = addr + max_strlen * sizeof(iov);
+		if (abbrev_end < addr)
+			abbrev_end = end;
 	} else {
-		tprintf("[");
-		for (i = 0; i < len; i++) {
-			if (i)
-				tprintf(", ");
-			tprintf("{");
-			printstr(tcp, (long) iov[i].iov_base,
-				iov[i].iov_len);
-			tprintf(", %lu}", (unsigned long)iov[i].iov_len);
-		}
-		tprintf("]");
+		abbrev_end = end;
 	}
-	free((char *) iov);
+	tprintf("[");
+	for (cur = addr; cur < end; cur += sizeof(iov)) {
+		if (cur > addr)
+			tprintf(", ");
+		if (cur >= abbrev_end) {
+			tprintf("...");
+			break;
+		}
+		if (umoven(tcp, cur, sizeof iov, (char *) &iov) < 0) {
+			tprintf("?");
+			failed = 1;
+			break;
+		}
+		tprintf("{");
+		printstr(tcp, (long) iov.iov_base, iov.iov_len);
+		tprintf(", %lu}", (unsigned long)iov.iov_len);
+	}
+	tprintf("]");
+	if (failed)
+		tprintf(" %#lx", addr);
 }
 
 int
diff --git a/mem.c b/mem.c
index 08a5f92..636644e 100644
--- a/mem.c
+++ b/mem.c
@@ -692,26 +692,43 @@
 unsigned long maxnodes;
 int err;
 {
-	int nlongs = (maxnodes + 8 * sizeof(long) - 1) / (8 * sizeof(long));
-	if (err || !abbrev(tcp) || nlongs > getpagesize() / sizeof(long)
-	    || nlongs == 0) {
-		long buf[nlongs];
-		if (umoven(tcp, ptr, nlongs * sizeof(long),
-			   (char *) buf) < 0)
-			tprintf(", %lx", ptr);
-		else {
-			int i;
-			tprintf(", {");
-			for (i = 0; i < nlongs; ++i) {
-				if (i > 0)
-					tprintf(", ");
-				tprintf("%#0*lx", (int) sizeof(long) * 2 + 2,
-					buf[i]);
-			}
-			tprintf("}");
+	unsigned long nlongs, size, end;
+
+	nlongs = (maxnodes + 8 * sizeof(long) - 1) / (8 * sizeof(long));
+	size = nlongs * sizeof(long);
+	end = ptr + size;
+	if (nlongs == 0 || ((err || verbose(tcp)) && (size * 8 == maxnodes)
+			    && (end > ptr))) {
+		unsigned long n, cur, abbrev_end;
+		int failed = 0;
+
+		if (abbrev(tcp)) {
+			abbrev_end = ptr + max_strlen * sizeof(long);
+			if (abbrev_end < ptr)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
 		}
+		tprintf(", {");
+		for (cur = ptr; cur < end; cur += sizeof(long)) {
+			if (cur > ptr)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(n), (char *) &n) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%#0*lx", (int) sizeof(long) * 2 + 2, n);
+		}
+		tprintf("}");
+		if (failed)
+			tprintf(" %#lx", ptr);
 	} else
-		tprintf(", %lx", ptr);
+		tprintf(", %#lx", ptr);
 	tprintf(", %lu", maxnodes);
 }
 
diff --git a/net.c b/net.c
index 103278d..ab71106 100644
--- a/net.c
+++ b/net.c
@@ -1082,44 +1082,51 @@
 unsigned long addr;
 unsigned long len;
 {
-	union {
-		char msg_control[len];
-		struct cmsghdr cmsg;
-	} u;
-	if (umoven(tcp, addr, len, u.msg_control) < 0) {
+	struct cmsghdr *cmsg = len < sizeof(struct cmsghdr) ?
+			       NULL : malloc(len);
+	if (cmsg == NULL || umoven(tcp, addr, len, (char *) cmsg) < 0) {
 		tprintf(", msg_control=%#lx", addr);
+		free(cmsg);
 		return;
 	}
 
-	tprintf(", {cmsg_len=%zu, cmsg_level=", u.cmsg.cmsg_len);
-	printxval(socketlayers, u.cmsg.cmsg_level, "SOL_???");
+	tprintf(", {cmsg_len=%zu, cmsg_level=", cmsg->cmsg_len);
+	printxval(socketlayers, cmsg->cmsg_level, "SOL_???");
 	tprintf(", cmsg_type=");
 
-	if (u.cmsg.cmsg_level == SOL_SOCKET) {
-		printxval(scmvals, u.cmsg.cmsg_type, "SCM_???");
+	if (cmsg->cmsg_level == SOL_SOCKET) {
+		unsigned long cmsg_len;
 
-		if (u.cmsg.cmsg_type == SCM_RIGHTS) {
-			int *fds = (int *) CMSG_DATA (&u.cmsg);
+		printxval(scmvals, cmsg->cmsg_type, "SCM_???");
+		cmsg_len = (len < cmsg->cmsg_len) ? len : cmsg->cmsg_len;
+
+		if (cmsg->cmsg_type == SCM_RIGHTS
+		    && CMSG_LEN(sizeof(int)) <= cmsg_len) {
+			int *fds = (int *) CMSG_DATA (cmsg);
 			int first = 1;
+
 			tprintf(", {");
-			while ((char *) fds < (u.msg_control
-					       + u.cmsg.cmsg_len)) {
+			while ((char *) fds < ((char *) cmsg + cmsg_len)) {
 				if (!first)
 					tprintf(", ");
 				tprintf("%d", *fds++);
 				first = 0;
 			}
 			tprintf("}}");
+			free(cmsg);
 			return;
 		}
-		if (u.cmsg.cmsg_type == SCM_CREDENTIALS
-		    && CMSG_LEN(sizeof(struct ucred)) <= u.cmsg.cmsg_len) {
-			struct ucred *uc = (struct ucred *) CMSG_DATA (&u.cmsg);
+		if (cmsg->cmsg_type == SCM_CREDENTIALS
+		    && CMSG_LEN(sizeof(struct ucred)) <= cmsg_len) {
+			struct ucred *uc = (struct ucred *) CMSG_DATA (cmsg);
+
 			tprintf("{pid=%ld, uid=%ld, gid=%ld}}",
 				(long)uc->pid, (long)uc->uid, (long)uc->gid);
+			free(cmsg);
 			return;
 		}
 	}
+	free(cmsg);
 	tprintf(", ...}");
 }
 
@@ -1138,7 +1145,8 @@
 	printsock(tcp, (long)msg.msg_name, msg.msg_namelen);
 
 	tprintf(", msg_iov(%lu)=", (unsigned long)msg.msg_iovlen);
-	tprint_iov(tcp, msg.msg_iovlen, (long) msg.msg_iov);
+	tprint_iov(tcp, (unsigned long)msg.msg_iovlen,
+		   (unsigned long)msg.msg_iov);
 
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
 	tprintf(", msg_controllen=%lu", (unsigned long)msg.msg_controllen);
diff --git a/process.c b/process.c
index badcba6..bc116a4 100644
--- a/process.c
+++ b/process.c
@@ -1225,34 +1225,53 @@
 sys_setgroups(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS_T *gidset;
-
 	if (entering(tcp)) {
+		unsigned long len, size, start, cur, end, abbrev_end;
+		GETGROUPS_T gid;
+		int failed = 0;
+
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
-		if (len <= 0) {
+		tprintf("%lu, ", len);
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS_T *) malloc(len * sizeof(GETGROUPS_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_setgroups: out of memory\n");
-			return -1;
+		start = tcp->u_arg[1];
+		if (start == 0) {
+			tprintf("NULL");
+			return 0;
 		}
-		if (!verbose(tcp))
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
 		}
-		free((char *) gidset);
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }
@@ -1261,38 +1280,62 @@
 sys_getgroups(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS_T *gidset;
+	unsigned long len;
 
 	if (entering(tcp)) {
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
+		tprintf("%lu, ", len);
 	} else {
+		unsigned long size, start, cur, end, abbrev_end;
+		GETGROUPS_T gid;
+		int failed = 0;
+
 		len = tcp->u_rval;
-		if (len <= 0) {
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS_T *) malloc(len * sizeof(GETGROUPS_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_getgroups: out of memory\n");
-			return -1;
-		}
-		if (!tcp->u_arg[1])
+		start = tcp->u_arg[1];
+		if (start == 0) {
 			tprintf("NULL");
-		else if (!verbose(tcp) || tcp->u_arg[0] == 0)
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+			return 0;
 		}
-		free((char *)gidset);
+		if (tcp->u_arg[0] == 0) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || tcp->u_arg[0] == 0 ||
+		    size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }
@@ -1302,34 +1345,53 @@
 sys_setgroups32(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS32_T *gidset;
-
 	if (entering(tcp)) {
+		unsigned long len, size, start, cur, end, abbrev_end;
+		GETGROUPS32_T gid;
+		int failed = 0;
+
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
-		if (len <= 0) {
+		tprintf("%lu, ", len);
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS32_T *) malloc(len * sizeof(GETGROUPS32_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_setgroups32: out of memory\n");
-			return -1;
+		start = tcp->u_arg[1];
+		if (start == 0) {
+			tprintf("NULL");
+			return 0;
 		}
-		if (!verbose(tcp))
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS32_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
 		}
-		free((char *) gidset);
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }
@@ -1338,38 +1400,58 @@
 sys_getgroups32(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS32_T *gidset;
+	unsigned long len;
 
 	if (entering(tcp)) {
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
+		tprintf("%lu, ", len);
 	} else {
+		unsigned long size, start, cur, end, abbrev_end;
+		GETGROUPS32_T gid;
+		int failed = 0;
+
 		len = tcp->u_rval;
-		if (len <= 0) {
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS32_T *) malloc(len * sizeof(GETGROUPS32_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_getgroups32: out of memory\n");
-			return -1;
-		}
-		if (!tcp->u_arg[1])
+		start = tcp->u_arg[1];
+		if (start == 0) {
 			tprintf("NULL");
-		else if (!verbose(tcp) || tcp->u_arg[0] == 0)
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS32_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+			return 0;
 		}
-		free((char *)gidset);
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || tcp->u_arg[0] == 0 ||
+		    size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }
diff --git a/stream.c b/stream.c
index 998fd8a..f01fe99 100644
--- a/stream.c
+++ b/stream.c
@@ -298,61 +298,69 @@
 sys_poll(tcp)
 struct tcb *tcp;
 {
-	struct pollfd *pollp;
+	struct pollfd fds;
+	unsigned nfds;
+	unsigned long size, start, cur, end, abbrev_end;
+	int failed = 0;
 
-	if (exiting(tcp)) {
-		int i;
-		int nfds = tcp->u_arg[1];
+	if (entering(tcp))
+		return 0;
 
-		if (nfds <= 0) {
-			tprintf("%#lx, %d, %ld\n",
-				tcp->u_arg[0], nfds, tcp->u_arg[2]);
-			return 0;
-		}
-		pollp = (struct pollfd *) malloc(nfds * sizeof(*pollp));
-		if (pollp == NULL) {
-			fprintf(stderr, "sys_poll: no memory\n");
-			tprintf("%#lx, %d, %ld",
-				tcp->u_arg[0], nfds, tcp->u_arg[2]);
-			return 0;
-		}
-		if (umoven(tcp, tcp->u_arg[0],
-			   (nfds * sizeof(*pollp)), (char *) pollp) < 0) {
-			tprintf("%#lx", tcp->u_arg[0]);
-		}
-		else {
-			tprintf("[");
-			for (i = 0; i < nfds; i++) {
-				if (i)
-					tprintf(", ");
-				if (pollp[i].fd < 0) {
-					tprintf("{fd=%d}", pollp[i].fd);
-					continue;
-				}
-				tprintf("{fd=%d, events=", pollp[i].fd);
-				printflags(pollflags, pollp[i].events,
-					   "POLL???");
-				if (!syserror(tcp) && pollp[i].revents) {
-					tprintf(", revents=");
-					printflags(pollflags, pollp[i].revents,
-						   "POLL???");
-				}
-				tprintf("}");
-			}
-			tprintf("]");
-		}
-		tprintf(", %d, ", nfds);
-#ifdef INFTIM
-		if (tcp->u_arg[2] == INFTIM)
-			tprintf("INFTIM");
-		else
-#endif
-			tprintf("%ld", tcp->u_arg[2]);
-		free(pollp);
+	nfds = tcp->u_arg[1];
+	size = sizeof(fds) * nfds;
+	start = tcp->u_arg[0];
+	end = start + size;
+	if (nfds == 0 || size / sizeof(fds) != nfds || end < start) {
+		tprintf("%#lx, %d, %ld",
+			tcp->u_arg[0], nfds, tcp->u_arg[2]);
+		return 0;
 	}
+	if (abbrev(tcp)) {
+		abbrev_end = start + max_strlen * sizeof(fds);
+		if (abbrev_end < start)
+			abbrev_end = end;
+	} else {
+		abbrev_end = end;
+	}
+	tprintf("[");
+	for (cur = start; cur < end; cur += sizeof(fds)) {
+		if (cur > start)
+			tprintf(", ");
+		if (cur >= abbrev_end) {
+			tprintf("...");
+			break;
+		}
+		if (umoven(tcp, cur, sizeof fds, (char *) &fds) < 0) {
+			tprintf("?");
+			failed = 1;
+			break;
+		}
+		if (fds.fd < 0) {
+			tprintf("{fd=%d}", fds.fd);
+			continue;
+		}
+		tprintf("{fd=%d, events=", fds.fd);
+		printflags(pollflags, fds.events, "POLL???");
+		if (!syserror(tcp) && fds.revents) {
+			tprintf(", revents=");
+			printflags(pollflags, fds.revents, "POLL???");
+		}
+		tprintf("}");
+	}
+	tprintf("]");
+	if (failed)
+		tprintf(" %#lx", start);
+	tprintf(", %d, ", nfds);
+#ifdef INFTIM
+	if (tcp->u_arg[2] == INFTIM)
+		tprintf("INFTIM");
+	else
+#endif
+		tprintf("%ld", tcp->u_arg[2]);
 	return 0;
 }
 
+
 #else /* !HAVE_SYS_POLL_H */
 int
 sys_poll(tcp)
diff --git a/system.c b/system.c
index 7bbcdcd..a1c057e 100644
--- a/system.c
+++ b/system.c
@@ -1813,23 +1813,25 @@
 {
 	struct __sysctl_args info;
 	int *name;
+	unsigned long size;
+
 	if (umove (tcp, tcp->u_arg[0], &info) < 0)
 		return printargs(tcp);
 
-	name = malloc (sizeof (int) * info.nlen);
+	size = sizeof (int) * (unsigned long) info.nlen;
+	name = (size / sizeof (int) != info.nlen) ? NULL : malloc (size);
 	if (name == NULL ||
-	    umoven(tcp, (unsigned long) info.name,
-		   sizeof (int) * info.nlen, (char *) name) < 0) {
-		if (name != NULL)
-			free(name);
-		tprintf("{%p, %d, %p, %p, %p, %Zu}",
-			info.name, info.nlen, info.oldval, info.oldlenp,
-			info.newval, info.newlen);
+	    umoven(tcp, (unsigned long) info.name, size, (char *) name) < 0) {
+		free(name);
+		if (entering(tcp))
+			tprintf("{%p, %d, %p, %p, %p, %Zu}",
+				info.name, info.nlen, info.oldval,
+				info.oldlenp, info.newval, info.newlen);
 		return 0;
 	}
 
 	if (entering(tcp)) {
-		int cnt = 0;
+		int cnt = 0, max_cnt;
 
 		tprintf("{{");
 
@@ -1919,13 +1921,16 @@
 			goto out;
 		}
 	out:
-		while (cnt < info.nlen)
+		max_cnt = abbrev(tcp) ? max_strlen : info.nlen;
+		while (cnt < max_cnt)
 			tprintf(", %x", name[cnt++]);
+		if (cnt < info.nlen)
+			tprintf(", ...");
 		tprintf("}, %d, ", info.nlen);
 	} else {
 		size_t oldlen;
-		umove(tcp, (size_t)info.oldlenp, &oldlen);
-		if (info.nlen >= 2
+		if (umove(tcp, (size_t)info.oldlenp, &oldlen) >= 0
+		    && info.nlen >= 2
 		    && ((name[0] == CTL_KERN
 			 && (name[1] == KERN_OSRELEASE
 			     || name[1] == KERN_OSTYPE
diff --git a/util.c b/util.c
index d92c0ea..e477cf1 100644
--- a/util.c
+++ b/util.c
@@ -532,15 +532,15 @@
 {
 	struct iovec *iov;
 	int i;
+	unsigned long size;
 
-
-	if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
-		fprintf(stderr, "dump: No memory");
+	size = sizeof(*iov) * (unsigned long) len;
+	if (size / sizeof(*iov) != len
+	    || (iov = (struct iovec *) malloc(size)) == NULL) {
+		fprintf(stderr, "out of memory\n");
 		return;
 	}
-	if (umoven(tcp, addr,
-		   len * sizeof *iov, (char *) iov) >= 0) {
-
+	if (umoven(tcp, addr, size, (char *) iov) >= 0) {
 		for (i = 0; i < len; i++) {
                         /* include the buffer number to make it easy to
                          * match up the trace with the source */