diff options
author | Andrew Fresh <afresh1@cvs.openbsd.org> | 2016-02-24 23:13:18 +0000 |
---|---|---|
committer | Andrew Fresh <afresh1@cvs.openbsd.org> | 2016-02-24 23:13:18 +0000 |
commit | e04bba9e44a36a8253a295fe94722b5d6266df6d (patch) | |
tree | da9b2d7d2f27b5088d31647224bd18c063e162be /gnu/usr.bin | |
parent | 6e832a598869a6e7229645cf5033f0ef4dd18ada (diff) |
Cope with ambiguous environments
from Ricardo Signes
ok deraadt@
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r-- | gnu/usr.bin/perl/perl.c | 51 | ||||
-rw-r--r-- | gnu/usr.bin/perl/vms/vms.c | 4 |
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]); |