Subject: Re: top chewing memory
To: None <mason@primenet.com.au, current-users@netbsd.org>
From: None <itojun@iijlab.net>
List: current-users
Date: 06/02/2000 13:40:11
>>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?

	The following patch prevent top to growing.  it seems to be introduced
	by tgoto.c 1.12 -> 1.13 (remove 1024 bytes limit in termcap entry).

	I still have two question:
	- is t_getstr supposed to return pointer to dynamically allocated
	  region?  manpage does not mention it
	- same question for tgetstr.
	if t_gettr/tgetstr returns pointer to dynamically allocated region, I
	see one more memory leak in tputs().

itojun


Index: lib/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 04:35:43
@@ -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: lib/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 04:35:44
@@ -345,6 +345,7 @@
 		 */
 		if (limit != NULL && (*limit < i)) {
 			errno = E2BIG;
+			free(s);
 			return NULL;
 		}
   	
@@ -356,6 +357,7 @@
 	} else {
 		_DIAGASSERT(limit != NULL);
 		*limit = i;
+		free(s);
 		return NULL;
 	}
 }
Index: lib/libterm/tgoto.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libterm/tgoto.c,v
retrieving revision 1.15
diff -u -r1.15 tgoto.c
--- tgoto.c	1999/09/16 11:45:49	1.15
+++ tgoto.c	2000/06/02 04:35:44
@@ -45,6 +45,7 @@
 #include <errno.h>
 #include <string.h>
 #include <termcap.h>
+#include <stdlib.h>
 
 #define	CTRL(c)	((c) & 037)
 
@@ -129,8 +130,14 @@
 	if (cp == 0) {
                 errno = EINVAL;
 toohard:
-                UP = old_up;
-                BC = old_bc;
+		if (UP != old_up) {
+			free(UP);
+			UP = old_up;
+		}
+		if (BC != old_bc) {
+			free(BC);
+			BC = old_bc;
+		}
 		return -1;
 	}
 	added[0] = '\0';
@@ -292,7 +299,13 @@
         }
         
         (void)strcpy(dp, added);
-        UP = old_up;
-        BC = old_bc;
+	if (UP != old_up) {
+		free(UP);
+		UP = old_up;
+	}
+	if (BC != old_bc) {
+		free(BC);
+		BC = old_bc;
+	}
 	return 0;
 }