Skip to content

Commit

Permalink
On VMS, %ENV in scalar context must call prime_env_iter()
Browse files Browse the repository at this point in the history
Otherwise it will return wrong results, unless other code happens to
have iterated over %ENV. This bug has probably existed forever.
  • Loading branch information
nwc10 authored and craigberry committed Sep 12, 2021
1 parent 62a7250 commit 0016477
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 3 deletions.
15 changes: 12 additions & 3 deletions pod/perldelta.pod
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,18 @@ L</Modules and Pragmata> section.

=over 4

=item XXX-some-platform

XXX
=item C<keys %ENV> on VMS returns consistent results

On VMS entries in the C<%ENV> hash are loaded from the OS environment on
first access, hence the first iteration of C<%ENV> requires the entire
environment to be scanned to find all possible keys. This initialisation had
always been done correctly for full iteration, but previously was not
happening for C<%ENV> in scalar context, meaning that C<scalar %ENV> would
return 0 if called before any other C<%ENV> access, or would only return the
count of keys accessed if there had been no iteration.

These bugs are now fixed - C<%ENV> and C<keys %ENV> in scalar context now
return the correct result - the count of all keys in the environment.

=back

Expand Down
13 changes: 13 additions & 0 deletions pp_hot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,19 @@ S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme, bool is_keys, bool has_targ)
}
}
else {
#if defined(DYNAMIC_ENV_FETCH) && defined(VMS)
/* maybe nothing set up %ENV for iteration yet...
do this always (not just if HvUSEDKEYS(hv) is currently 0) because
we ought to give a *consistent* answer to "how many keys?"
whether we ask this op in scalar context, or get the list of all
keys then check its length, and whether we do either with or without
an %ENV lookup first. prime_env_iter() returns quickly if nothing
needs doing. */
if (SvRMAGICAL((const SV *)hv)
&& mg_find((const SV *)hv, PERL_MAGIC_env)) {
prime_env_iter();
}
#endif
i = HvUSEDKEYS(hv);
if (is_bool) {
sv = i ? &PL_sv_yes : &PL_sv_zero;
Expand Down
9 changes: 9 additions & 0 deletions t/op/each.t
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,15 @@ for my $k (qw(each keys values)) {
ok(!$warned, "no warnings 'internal' silences each() after insert warnings");
}

fresh_perl_like('$a = keys %ENV; $b = () = keys %ENV; $c = keys %ENV; print qq=$a,$b,$c=',
qr/^([1-9][0-9]*),\1,\1$/,
undef,
'keys %ENV in scalar context triggers prime_env_iter if needed');
fresh_perl_like('$a = $ENV{PATH}; $a = $ENV{q=DCL$PATH=}; $a = keys %ENV; $b = () = keys %ENV; $c = keys %ENV; print qq=$a,$b,$c=',
qr/^([1-9][0-9]*),\1,\1$/,
undef,
'%ENV lookup, and keys %ENV in scalar context remain consistent');

use feature 'refaliasing';
no warnings 'experimental::refaliasing';
$a = 7;
Expand Down

0 comments on commit 0016477

Please sign in to comment.