Subject: try again: unsetenv memory leak fix
To: None <tech-userlevel@netbsd.org>
From: Masaru OKI <oki@netbsd.org>
List: tech-userlevel
Date: 06/30/2003 04:29:27
Hi,
I've fixed a bug pointed out by david.  thanks!
please review it.

regards,
-- 
Masaru OKI <oki@netbsd.org>


Index: __unsetenv13.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdlib/__unsetenv13.c,v
retrieving revision 1.2
diff -u -r1.2 __unsetenv13.c
--- __unsetenv13.c	2003/04/13 17:39:13	1.2
+++ __unsetenv13.c	2003/06/29 19:14:47
@@ -68,6 +68,7 @@
 #endif
 
 extern char **environ;
+char **__alloced_env;
 
 /*
  * unsetenv(name) --
@@ -81,7 +82,7 @@
 unsetenv(name)
 	const char *name;
 {
-	char **p;
+	char **p, **mp;
 	int offset;
 
 	_DIAGASSERT(name != NULL);
@@ -94,10 +95,18 @@
 #endif
 
 	rwlock_wrlock(&__environ_lock);
-	while (__findenv(name, &offset))	/* if set multiple times */
-		for (p = &environ[offset];; ++p)
+	while (__findenv(name, &offset)) {	/* if set multiple times */
+		if (__alloced_env != 0 && __alloced_env[offset] != 0) {
+			free(__alloced_env[offset]);
+			mp = &__alloced_env[offset];
+		}
+		for (p = &environ[offset];; ++p) {
 			if (!(*p = *(p + 1)))
 				break;
+			if (__alloced_env)
+				*mp = *(mp + 1);
+		}
+	}
 	rwlock_unlock(&__environ_lock);
 
 #ifndef __LIBC12_SOURCE__
Index: setenv.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdlib/setenv.c,v
retrieving revision 1.22
diff -u -r1.22 setenv.c
--- setenv.c	2003/04/07 13:41:14	1.22
+++ setenv.c	2003/06/29 19:14:47
@@ -61,6 +61,8 @@
 
 extern char **environ;
 
+char **__alloced_env;		/* if allocated space before */
+
 /*
  * setenv --
  *	Set the value of the environmental variable "name" to be
@@ -72,7 +74,6 @@
 	const char *value;
 	int rewrite;
 {
-	static int alloced;			/* if allocated space before */
 	char *c;
 	const char *cc;
 	size_t l_value;
@@ -101,16 +102,28 @@
 		char **p;
 
 		for (p = environ, cnt = 0; *p; ++p, ++cnt);
-		if (alloced) {			/* just increase size */
+		if (__alloced_env) {	/* just increase size */
 			environ = realloc(environ,
 			    (size_t)(sizeof(char *) * (cnt + 2)));
 			if (!environ) {
 				rwlock_unlock(&__environ_lock);
 				return (-1);
 			}
+			__alloced_env = realloc(__alloced_env,
+			    (size_t)(sizeof(char *) * (cnt + 1)));
+			if (!__alloced_env) {
+				rwlock_unlock(&__environ_lock);
+				return (-1);
+			}
+			__alloced_env[cnt] = 0;
 		}
 		else {				/* get new space */
-			alloced = 1;		/* copy old entries into it */
+			/* copy old entries into it */
+			__alloced_env = calloc(cnt + 1, sizeof(char *));
+			if (!__alloced_env) {
+				rwlock_unlock(&__environ_lock);
+				return (-1);
+			}
 			p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
 			if (!p) {
 				rwlock_unlock(&__environ_lock);
@@ -124,11 +137,14 @@
 	}
 	for (cc = name; *cc && *cc != '='; ++cc)/* no `=' in name */
 		continue;
+	if (__alloced_env[offset] != 0)
+		free(__alloced_env[offset]);
 	if (!(environ[offset] =			/* name + `=' + value */
 	    malloc((size_t)((int)(cc - name) + l_value + 2)))) {
 		rwlock_unlock(&__environ_lock);
 		return (-1);
 	}
+	__alloced_env[offset] = environ[offset];
 	for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
 	for (*c++ = '='; (*c++ = *value++) != '\0'; );
 	rwlock_unlock(&__environ_lock);