Module Name:    src
Committed By:   tron
Date:           Sat Sep 25 18:11:40 UTC 2010

Modified Files:
        src/lib/libc/stdlib: getenv.c local.h setenv.c unsetenv.c

Log Message:
Remember memory used by allocated environment variables instead of
using a bitmap. This deals with the case where a variable is first
set via setenv(3) or putenv(3), then overwritten by changing
"environ" directory and afterwards overwritten with setenv(3) again.

This stops "zsh" from crashing under NetBSD-current.

Code reviewed by Christos Zoulas.


To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/lib/libc/stdlib/getenv.c
cvs rdiff -u -r1.3 -r1.4 src/lib/libc/stdlib/local.h
cvs rdiff -u -r1.35 -r1.36 src/lib/libc/stdlib/setenv.c
cvs rdiff -u -r1.5 -r1.6 src/lib/libc/stdlib/unsetenv.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/stdlib/getenv.c
diff -u src/lib/libc/stdlib/getenv.c:1.20 src/lib/libc/stdlib/getenv.c:1.21
--- src/lib/libc/stdlib/getenv.c:1.20	Thu Sep 23 17:30:49 2010
+++ src/lib/libc/stdlib/getenv.c	Sat Sep 25 18:11:40 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: getenv.c,v 1.20 2010/09/23 17:30:49 christos Exp $	*/
+/*	$NetBSD: getenv.c,v 1.21 2010/09/25 18:11:40 tron Exp $	*/
 
 /*
  * Copyright (c) 1987, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)getenv.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: getenv.c,v 1.20 2010/09/23 17:30:49 christos Exp $");
+__RCSID("$NetBSD: getenv.c,v 1.21 2010/09/25 18:11:40 tron Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -43,15 +43,14 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
-#include <bitstring.h>
 #include "reentrant.h"
 #include "local.h"
 
 #ifdef _REENTRANT
 rwlock_t __environ_lock = RWLOCK_INITIALIZER;
 #endif
-bitstr_t *__environ_malloced;
-static size_t environ_bitlen;
+char **__environ_malloced;
+static size_t environ_malloced_len;
 
 __weak_alias(getenv_r, _getenv_r)
 
@@ -104,28 +103,27 @@
 int
 __allocenv(int offset)
 {
-	bitstr_t *s;
+	char **p;
 	size_t nl;
 
 	if (offset == -1) {
 		char **ptr;
-		for (ptr = environ, offset = 0; *ptr; ptr++)
+		for (ptr = environ, offset = 0; *ptr != NULL; ptr++)
 			offset++;
 	}
-	nl = bitstr_size(offset + 2);
-	if (__environ_malloced == NULL) {
-		s = malloc(nl);
-	} else if (environ_bitlen < nl)
-		s = realloc(__environ_malloced, nl);
-	else
+
+	if ((size_t)offset < environ_malloced_len)
 		return 0;
 
-	if (s == NULL)
+	nl = offset + 2;
+	p = realloc(__environ_malloced, nl * sizeof(char *));
+	if (p == NULL)
 		return -1;
 
-	(void)memset(&s[environ_bitlen], 0, nl - environ_bitlen);
-	environ_bitlen = nl;
-	__environ_malloced = s;
+	(void)memset(&p[environ_malloced_len], 0,
+	    (nl - environ_malloced_len) * sizeof(char *));
+	environ_malloced_len = nl;
+	__environ_malloced = p;
 
 	return 0;
 }

Index: src/lib/libc/stdlib/local.h
diff -u src/lib/libc/stdlib/local.h:1.3 src/lib/libc/stdlib/local.h:1.4
--- src/lib/libc/stdlib/local.h:1.3	Thu Sep 23 17:30:49 2010
+++ src/lib/libc/stdlib/local.h	Sat Sep 25 18:11:40 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: local.h,v 1.3 2010/09/23 17:30:49 christos Exp $	*/
+/*	$NetBSD: local.h,v 1.4 2010/09/25 18:11:40 tron Exp $	*/
 
 /*
  * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
@@ -32,4 +32,4 @@
 #endif
 
 extern char **environ;
-extern bitstr_t *__environ_malloced;
+extern char **__environ_malloced;

Index: src/lib/libc/stdlib/setenv.c
diff -u src/lib/libc/stdlib/setenv.c:1.35 src/lib/libc/stdlib/setenv.c:1.36
--- src/lib/libc/stdlib/setenv.c:1.35	Fri Sep 24 14:31:15 2010
+++ src/lib/libc/stdlib/setenv.c	Sat Sep 25 18:11:40 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: setenv.c,v 1.35 2010/09/24 14:31:15 christos Exp $	*/
+/*	$NetBSD: setenv.c,v 1.36 2010/09/25 18:11:40 tron Exp $	*/
 
 /*
  * Copyright (c) 1987, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)setenv.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: setenv.c,v 1.35 2010/09/24 14:31:15 christos Exp $");
+__RCSID("$NetBSD: setenv.c,v 1.36 2010/09/25 18:11:40 tron Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -44,7 +44,6 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
-#include <bitstring.h>
 #include "reentrant.h"
 #include "local.h"
 
@@ -56,9 +55,6 @@
 extern rwlock_t __environ_lock;
 #endif
 
-extern char **environ;
-extern bitstr_t *__environ_malloced;
-
 /*
  * setenv --
  *	Set the value of the environmental variable "name" to be
@@ -76,7 +72,9 @@
 	_DIAGASSERT(name != NULL);
 	_DIAGASSERT(value != NULL);
 
-	rwlock_wrlock(&__environ_lock);
+	if (rwlock_wrlock(&__environ_lock) != 0)
+		return -1;
+
 	/* find if already exists */
 	c = __findenv(name, &offset);
 
@@ -113,13 +111,15 @@
 	/* name + `=' + value */
 	if ((c = malloc(size + l_value + 2)) == NULL)
 		goto bad;
-	if (bit_test(__environ_malloced, offset))
-		free(environ[offset]);
+
 	environ[offset] = c;
 	(void)memcpy(c, name, size);
 	c += size;
 	*c++ = '=';
-	bit_set(__environ_malloced, offset);
+
+	free(__environ_malloced[offset]);
+	__environ_malloced[offset] = c;
+
 copy:
 	(void)memcpy(c, value, l_value + 1);
 good:

Index: src/lib/libc/stdlib/unsetenv.c
diff -u src/lib/libc/stdlib/unsetenv.c:1.5 src/lib/libc/stdlib/unsetenv.c:1.6
--- src/lib/libc/stdlib/unsetenv.c:1.5	Fri Sep 24 14:34:44 2010
+++ src/lib/libc/stdlib/unsetenv.c	Sat Sep 25 18:11:40 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: unsetenv.c,v 1.5 2010/09/24 14:34:44 christos Exp $	*/
+/*	$NetBSD: unsetenv.c,v 1.6 2010/09/25 18:11:40 tron Exp $	*/
 
 /*
  * Copyright (c) 1987, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "from: @(#)setenv.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: unsetenv.c,v 1.5 2010/09/24 14:34:44 christos Exp $");
+__RCSID("$NetBSD: unsetenv.c,v 1.6 2010/09/25 18:11:40 tron Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -53,10 +53,8 @@
  *	Delete environmental variable "name".
  */
 int
-unsetenv(name)
-	const char *name;
+unsetenv(const char *name)
 {
-	char **p;
 	int offset;
 
 	_DIAGASSERT(name != NULL);
@@ -66,22 +64,22 @@
 		return -1;
 	}
 
-	rwlock_wrlock(&__environ_lock);
+	if (rwlock_wrlock(&__environ_lock) != 0)
+		return -1;
 
 	if (__allocenv(-1) == -1)
 		return -1;
 
-	while (__findenv(name, &offset)) {	/* if set multiple times */
-		if (bit_test(__environ_malloced, offset))
-			free(environ[offset]);
-		for (p = &environ[offset];; ++p, ++offset) {
-			if (bit_test(__environ_malloced, offset + 1))
-				bit_set(__environ_malloced, offset);
-			else
-				bit_clear(__environ_malloced, offset);
-			if (!(*p = *(p + 1)))
-				break;
+	while (__findenv(name, &offset) != NULL ) { /* if set multiple times */
+		free(__environ_malloced[offset]);
+
+		while (environ[offset] != NULL) {
+			environ[offset] = environ[offset + 1];
+			__environ_malloced[offset] =
+			    __environ_malloced[offset + 1];
+			offset++;
 		}
+		__environ_malloced[offset] = NULL;
 	}
 	rwlock_unlock(&__environ_lock);
 

Reply via email to