summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authortron <tron@NetBSD.org>2010-09-25 18:11:40 +0000
committertron <tron@NetBSD.org>2010-09-25 18:11:40 +0000
commit5cdca2e60020da2dfd58990aada65b6d71aab939 (patch)
treed558847cd606f13e38a295044af4770a0d99a4d0 /lib
parent15ed98d439d987f17cc3d8d7e7a1d20194be0586 (diff)
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/stdlib/getenv.c32
-rw-r--r--lib/libc/stdlib/local.h4
-rw-r--r--lib/libc/stdlib/setenv.c20
-rw-r--r--lib/libc/stdlib/unsetenv.c30
4 files changed, 41 insertions, 45 deletions
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index f4143339f13..ef78366979a 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -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 @@ __RCSID("$NetBSD: getenv.c,v 1.20 2010/09/23 17:30:49 christos Exp $");
#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 @@ out:
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;
}
diff --git a/lib/libc/stdlib/local.h b/lib/libc/stdlib/local.h
index 64c8fb9c99a..a8cd36e7e38 100644
--- a/lib/libc/stdlib/local.h
+++ b/lib/libc/stdlib/local.h
@@ -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 @@ extern rwlock_t __environ_lock;
#endif
extern char **environ;
-extern bitstr_t *__environ_malloced;
+extern char **__environ_malloced;
diff --git a/lib/libc/stdlib/setenv.c b/lib/libc/stdlib/setenv.c
index e9352d85ef9..07e8ff4866b 100644
--- a/lib/libc/stdlib/setenv.c
+++ b/lib/libc/stdlib/setenv.c
@@ -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 @@ __RCSID("$NetBSD: setenv.c,v 1.35 2010/09/24 14:31:15 christos Exp $");
#include <errno.h>
#include <stdlib.h>
#include <string.h>
-#include <bitstring.h>
#include "reentrant.h"
#include "local.h"
@@ -56,9 +55,6 @@ __weak_alias(setenv,_setenv)
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 @@ setenv(const char *name, const char *value, int rewrite)
_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 @@ setenv(const char *name, const char *value, int rewrite)
/* 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:
diff --git a/lib/libc/stdlib/unsetenv.c b/lib/libc/stdlib/unsetenv.c
index 8fa4f40b267..1b67e56796e 100644
--- a/lib/libc/stdlib/unsetenv.c
+++ b/lib/libc/stdlib/unsetenv.c
@@ -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 @@ __RCSID("$NetBSD: unsetenv.c,v 1.5 2010/09/24 14:34:44 christos Exp $");
* 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 @@ unsetenv(name)
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);