summaryrefslogtreecommitdiff
path: root/gnu/usr.bin
diff options
context:
space:
mode:
authorAndrew Fresh <afresh1@cvs.openbsd.org>2016-02-24 23:13:18 +0000
committerAndrew Fresh <afresh1@cvs.openbsd.org>2016-02-24 23:13:18 +0000
commite04bba9e44a36a8253a295fe94722b5d6266df6d (patch)
treeda9b2d7d2f27b5088d31647224bd18c063e162be /gnu/usr.bin
parent6e832a598869a6e7229645cf5033f0ef4dd18ada (diff)
Cope with ambiguous environments
from Ricardo Signes ok deraadt@
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r--gnu/usr.bin/perl/perl.c51
-rw-r--r--gnu/usr.bin/perl/vms/vms.c4
2 files changed, 52 insertions, 3 deletions
diff --git a/gnu/usr.bin/perl/perl.c b/gnu/usr.bin/perl/perl.c
index 5000d7981bb..be79d1b17a3 100644
--- a/gnu/usr.bin/perl/perl.c
+++ b/gnu/usr.bin/perl/perl.c
@@ -4277,23 +4277,70 @@ S_init_postdump_symbols(pTHX_ int argc, char **argv, char **env)
}
if (env) {
char *s, *old_var;
+ STRLEN nlen;
SV *sv;
+ HV *dups = newHV();
+
for (; *env; env++) {
old_var = *env;
if (!(s = strchr(old_var,'=')) || s == old_var)
continue;
+ nlen = s - old_var;
#if defined(MSDOS) && !defined(DJGPP)
*s = '\0';
(void)strupr(old_var);
*s = '=';
#endif
- sv = newSVpv(s+1, 0);
- (void)hv_store(hv, old_var, s - old_var, sv, 0);
+ if (hv_exists(hv, old_var, nlen)) {
+ const char *name = savepvn(old_var, nlen);
+
+ /* make sure we use the same value as getenv(), otherwise code that
+ uses getenv() (like setlocale()) might see a different value to %ENV
+ */
+ sv = newSVpv(PerlEnv_getenv(name), 0);
+
+ /* keep a count of the dups of this name so we can de-dup environ later */
+ if (hv_exists(dups, name, nlen))
+ ++SvIVX(*hv_fetch(dups, name, nlen, 0));
+ else
+ (void)hv_store(dups, name, nlen, newSViv(1), 0);
+
+ Safefree(name);
+ }
+ else {
+ sv = newSVpv(s+1, 0);
+ }
+ (void)hv_store(hv, old_var, nlen, sv, 0);
if (env_is_not_environ)
mg_set(sv);
}
+ if (HvKEYS(dups)) {
+ /* environ has some duplicate definitions, remove them */
+ HE *entry;
+ hv_iterinit(dups);
+ while ((entry = hv_iternext_flags(dups, 0))) {
+ STRLEN nlen;
+ const char *name = HePV(entry, nlen);
+ IV count = SvIV(HeVAL(entry));
+ IV i;
+ SV **valp = hv_fetch(hv, name, nlen, 0);
+
+ assert(valp);
+
+ /* try to remove any duplicate names, depending on the
+ * implementation used in my_setenv() the iteration might
+ * not be necessary, but let's be safe.
+ */
+ for (i = 0; i < count; ++i)
+ my_setenv(name, 0);
+
+ /* and set it back to the value we set $ENV{name} to */
+ my_setenv(name, SvPV_nolen(*valp));
+ }
+ }
+ SvREFCNT_dec_NN(dups);
}
#endif /* USE_ENVIRON_ARRAY */
#endif /* !PERL_MICRO */
diff --git a/gnu/usr.bin/perl/vms/vms.c b/gnu/usr.bin/perl/vms/vms.c
index 0f1fb5ed2d8..344b61b3752 100644
--- a/gnu/usr.bin/perl/vms/vms.c
+++ b/gnu/usr.bin/perl/vms/vms.c
@@ -1352,7 +1352,9 @@ prime_env_iter(void)
if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
char *start;
int j;
- for (j = 0; environ[j]; j++) {
+ /* Start at the end, so if there is a duplicate we keep the first one. */
+ for (j = 0; environ[j]; j++);
+ for (j--; j >= 0; j--) {
if (!(start = strchr(environ[j],'='))) {
if (ckWARN(WARN_INTERNAL))
Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);