Subject: please review: unsetenv memory leak fix
To: None <tech-userlevel@netbsd.org>
From: Masaru OKI <oki@netbsd.org>
List: tech-userlevel
Date: 06/28/2003 01:39:55
Hi,
unsetenv(3) doesn't call free(3) with environment variable string.
following diff is fixed the problem.
If it is looks good, I'll commit it later.

-- 
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/27 14:44:00
@@ -68,6 +68,8 @@
 #endif
 
 extern char **environ;
+extern int __environ_alloced;
+extern int *__env_is_malloced;
 
 /*
  * unsetenv(name) --
@@ -94,10 +96,13 @@
 #endif
 
 	rwlock_wrlock(&__environ_lock);
-	while (__findenv(name, &offset))	/* if set multiple times */
+	while (__findenv(name, &offset)) {	/* if set multiple times */
+		if (__environ_alloced == 1 && __env_is_malloced[offset] == 1)
+			free(environ[offset]);
 		for (p = &environ[offset];; ++p)
 			if (!(*p = *(p + 1)))
 				break;
+	}
 	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/27 14:44:01
@@ -61,6 +61,9 @@
 
 extern char **environ;
 
+int __environ_alloced;			/* if allocated space before */
+int *__env_is_malloced;
+
 /*
  * setenv --
  *	Set the value of the environmental variable "name" to be
@@ -72,7 +75,6 @@
 	const char *value;
 	int rewrite;
 {
-	static int alloced;			/* if allocated space before */
 	char *c;
 	const char *cc;
 	size_t l_value;
@@ -101,21 +103,29 @@
 		char **p;
 
 		for (p = environ, cnt = 0; *p; ++p, ++cnt);
-		if (alloced) {			/* just increase size */
+		if (__environ_alloced) {	/* just increase size */
 			environ = realloc(environ,
 			    (size_t)(sizeof(char *) * (cnt + 2)));
 			if (!environ) {
 				rwlock_unlock(&__environ_lock);
 				return (-1);
 			}
+			__env_is_malloced = realloc(__env_is_malloced,
+			    (size_t)(sizeof(int) * (cnt + 2)));
 		}
 		else {				/* get new space */
-			alloced = 1;		/* copy old entries into it */
+			__environ_alloced = 1;	/* copy old entries into it */
 			p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
 			if (!p) {
 				rwlock_unlock(&__environ_lock);
 				return (-1);
 			}
+			__env_is_malloced = calloc(cnt, sizeof(int));
+			if (!__env_is_malloced) {
+				free(p);
+				rwlock_unlock(&__environ_lock);
+				return (-1);
+			}
 			memcpy(p, environ, cnt * sizeof(char *));
 			environ = p;
 		}
@@ -124,11 +134,14 @@
 	}
 	for (cc = name; *cc && *cc != '='; ++cc)/* no `=' in name */
 		continue;
+	if (__env_is_malloced[offset] == 1)
+		free(environ[offset]);
 	if (!(environ[offset] =			/* name + `=' + value */
 	    malloc((size_t)((int)(cc - name) + l_value + 2)))) {
 		rwlock_unlock(&__environ_lock);
 		return (-1);
 	}
+	__env_is_malloced[offset] = 1;
 	for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
 	for (*c++ = '='; (*c++ = *value++) != '\0'; );
 	rwlock_unlock(&__environ_lock);