Subject: Re: top chewing memory
To: None <mason@primenet.com.au>
From: None <itojun@iijlab.net>
List: current-users
Date: 06/02/2000 10:50:03
>Geoff Wing <mason@primenet.com.au> typed:
>:anyone else getting top leaking memory or just me.
>:% top -s 0
>
>Whoops, just noticed that Mason Loring Bliss has already done a send-pr
>on this.  That's what I get for noticing a problem before I go to sleep
>and posting about it just after I wake up :-)

	it looks to me like follows:
	- cgetstr() calls malloc (as documented in manpage), and returns
	  pointer to malloc'ed region via 3rd arg
	  bug: leaks memory when realloc fails
	- t_getstr does not free the region returned by cgetstr().
	  not sure what is the intended behavior (should it return a pointer
	  to malloc'ed region, or not).
	  bug: it leaks memory when area == NULL.
	could someone enlighten me on how t_getstr should behave?

itojun


(gdb) bt
#0  0x8070a3d in malloc ()
#1  0x8055fe7 in cgetstr ()
#2  0x804d0ec in t_getstr ()
#3  0x804c832 in t_goto ()
#4  0x804b181 in Move_to (x=49, y=7)
    at /home/itojun/NetBSD/src/usr.bin/top/screen.c:508
#5  0x804aa6d in line_update (old=0x8096080 "00  0.07%  0.05% top", 
    new=0x8083612 "7  0.00%  0.00% sshd", start=0, line=7)
    at /home/itojun/NetBSD/src/usr.bin/top/display.c:1097
#6  0x804a3ca in u_process (line=1, 
    newline=0x80835e0 "  235 root       2    0   372K 1232K sleep     0:17  0.00%  0.00% sshd") at /home/itojun/NetBSD/src/usr.bin/top/display.c:721
#7  0x8048b8d in main (argc=3, argv=0xbfbfdae8)
    at /home/itojun/NetBSD/src/usr.bin/top/top.c:560
#8  0x80481c5 in ___start ()


Index: libc/gen/getcap.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/gen/getcap.c,v
retrieving revision 1.32
diff -u -r1.32 getcap.c
--- getcap.c	2000/01/22 22:19:10	1.32
+++ getcap.c	2000/06/02 01:49:07
@@ -249,7 +249,7 @@
 	char *r_end, *rp = NULL, **db_p;	/* pacify gcc */
 	int myfd = 0, eof, foundit, retval;
 	size_t clen;
-	char *record, *cbuf;
+	char *record, *cbuf, *newrecord;
 	int tc_not_resolved;
 	char pbuf[_POSIX_PATH_MAX];
 	
@@ -435,13 +435,15 @@
 
 					pos = rp - record;
 					newsize = r_end - record + BFRAG;
-					record = realloc(record, newsize);
-					if (record == NULL) {
+					newrecord = realloc(record, newsize);
+					if (newrecord == NULL) {
+						free(record);
 						if (myfd)
 							(void)close(fd);
 						errno = ENOMEM;
 						return (-2);
 					}
+					record = newrecord;
 					r_end = record + newsize;
 					rp = record + pos;
 				}
@@ -577,14 +579,16 @@
 				newsize = r_end - record + diff + BFRAG;
 				tcpos = tcstart - record;
 				tcposend = tcend - record;
-				record = realloc(record, newsize);
-				if (record == NULL) {
+				newrecord = realloc(record, newsize);
+				if (newrecord == NULL) {
+					free(record);
 					if (myfd)
 						(void)close(fd);
 					free(icap);
 					errno = ENOMEM;
 					return (-2);
 				}
+				record = newrecord;
 				r_end = record + newsize;
 				rp = record + pos;
 				tcstart = record + tcpos;
@@ -615,12 +619,15 @@
 	if (myfd)
 		(void)close(fd);
 	*len = rp - record - 1;	/* don't count NUL */
-	if (r_end > rp)
-		if ((record = 
+	if (r_end > rp) {
+		if ((newrecord = 
 		     realloc(record, (size_t)(rp - record))) == NULL) {
+			free(record);
 			errno = ENOMEM;
 			return (-2);
 		}
+		record = newrecord;
+	}
 		
 	*cap = record;
 	if (tc_not_resolved)
@@ -887,7 +894,7 @@
 	const char *bp;
 	char *mp;
 	int len;
-	char *mem;
+	char *mem, *newmem;
 
 	_DIAGASSERT(buf != NULL);
 	_DIAGASSERT(cap != NULL);
@@ -978,8 +985,11 @@
 		if (m_room == 0) {
 			size_t size = mp - mem;
 
-			if ((mem = realloc(mem, size + SFRAG)) == NULL)
+			if ((newmem = realloc(mem, size + SFRAG)) == NULL) {
+				free(mem);
 				return (-2);
+			}
+			mem = newmem;
 			m_room = SFRAG;
 			mp = mem + size;
 		}
@@ -991,9 +1001,13 @@
 	/*
 	 * Give back any extra memory and return value and success.
 	 */
-	if (m_room != 0)
-		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
+	if (m_room != 0) {
+		if ((newmem = realloc(mem, (size_t)(mp - mem))) == NULL) {
+			free(mem);
 			return (-2);
+		}
+		mem = newmem;
+	}
 	*str = mem;
 	return (len);
 }
@@ -1018,7 +1032,7 @@
 	const char *bp;
 	char *mp;
 	int len;
-	char *mem;
+	char *mem, *newmem;
 
 	_DIAGASSERT(buf != NULL);
 	_DIAGASSERT(cap != NULL);
@@ -1058,8 +1072,11 @@
 		if (m_room == 0) {
 			size_t size = mp - mem;
 
-			if ((mem = realloc(mem, size + SFRAG)) == NULL)
+			if ((newmem = realloc(mem, size + SFRAG)) == NULL) {
+				free(mem);
 				return (-2);
+			}
+			mem = newmem;
 			m_room = SFRAG;
 			mp = mem + size;
 		}
@@ -1071,9 +1088,13 @@
 	/*
 	 * Give back any extra memory and return value and success.
 	 */
-	if (m_room != 0)
-		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
+	if (m_room != 0) {
+		if ((newmem = realloc(mem, (size_t)(mp - mem))) == NULL) {
+			free(mem);
 			return (-2);
+		}
+		mem = newmem;
+	}
 	*str = mem;
 	return (len);
 }
Index: libterm/termcap.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libterm/termcap.c,v
retrieving revision 1.31
diff -u -r1.31 termcap.c
--- termcap.c	2000/05/28 09:58:15	1.31
+++ termcap.c	2000/06/02 01:49:08
@@ -345,6 +345,7 @@
 		 */
 		if (limit != NULL && (*limit < i)) {
 			errno = E2BIG;
+			free(s);
 			return NULL;
 		}
   	
@@ -352,10 +353,11 @@
 		*area += i + 1;
 		if (limit != NULL) *limit -= i;
   	
-		return (s);
+		return (s);	/*XXX is it correct?*/
 	} else {
 		_DIAGASSERT(limit != NULL);
 		*limit = i;
+		free(s);
 		return NULL;
 	}
 }