On 9 November 2013 00:35, Steve Hay <steve.m....@googlemail.com> wrote:
> On 7 November 2013 20:05, Jan Kaluza <jkal...@redhat.com> wrote:
[...]
>> All cgi*.t tests fails since commit r1491887.
>>
>
> r1491887 restored the running of the tests in t/modperl/local_env.t,
> which itself fails for me on Windows. I've been looking at why, but
> can't quite figure it out.
>
> All but the last test pass. The last test checks that a copy of %ENV
> taken before making local()ized changes to it matches the restored
> %ENV after the local() scope has been exited. It fails because %ENV
> has one more item in it than it did originally. The original had a key
> named 'SystemRoot'; the restored version has that and another key
> named 'SYSTEMROOT' too. On Windows, environment variable names (like
> file names and registry keys and many other things) are
> case-preserving but case-insensitive; clearly something has gone amiss
> there.
>
> The extra key creeps in within t_cmp(): it isn't there before
>
>     t_debug("expected: " . struct_as_string(0, $expected));
>
> but is there after it! Inside struct_as_string() we mistakenly go into
> the !HAS_DUMPER code path due to a wrong test for perl >= 5.6.0 [which
> I've just fixed in r1540227] and do this:
>
>             my @data = ();
>             for my $key (keys %{ $_[0] }) {
>                 push @data,
>                     "$key => " .
>                     struct_as_string($level+1, $_[0]->{$key});
>             }
>             return join "\n", "{", map({"$pad$_,"} @data), "$spad\}";
>
> which looks perfectly reasonable but wrongly causes the extra key to
> appear in %ENV. (Perhaps it gets SystemRoot from keys() but that gets
> uppercased when looking up the value a few lines later, causing the
> SYSTEMROOT key to be auto-vivified? I haven't checked that theory yet
> though.)

That seems to be the problem: If I insert this:

    my $old1 = join "\n", grep /^sy/i, keys %copy_ENV;
    my $dummy1 = $copy_ENV{SystemRoot};
    my $new1 = join "\n", grep /^sy/i, keys %copy_ENV;
    t_debug("Before:\n$old1\nAfter:\n$new1");

    my $old2 = join "\n", grep /^sy/i, keys %ENV;
    my $dummy2 = $ENV{SystemRoot};
    my $new2 = join "\n", grep /^sy/i, keys %ENV;
    t_debug("Before:\n$old2\nAfter:\n$new2");

just before:

    ok t_cmp(\%copy_ENV, \%ENV, "\%ENV was restored correctly");

in t/response/ModPerl/local_env.pm then I get:

# Before:
# SystemRoot
# After:
# SystemRoot
# Before:
# SystemRoot
# After:
# SYSTEMROOT
# SystemRoot

so the magical %ENV (but obviously not the lexical %copy_ENV)
originally has only SystemRoot in it, but gets SYSTEMROOT in it too
after looking up SystemRoot [sic]!


>
> I'm struggling to understand the handling of %ENV in both perl and
> mod_perl, but running the local_env.pm code outside of the mod_perl
> environment I can't reproduce the problem, so it seems like something
> in mod_perl, perhaps in modperl_env.c, that is at fault.
>
> Is it missing the "magic" that perl has to effect the
> case-insensitivity? [...]

Perl sets up a magic vtable for %ENV & elements in mg_vtable.h (order
is get/set/len/clear//free/copy/dup/local):

PL_magic_vtables[want_vtbl_env] = { 0, Perl_magic_set_all_env, 0,
Perl_magic_clear_all_env, 0, 0, 0, 0 };
PL_magic_vtables[want_vtbl_envelem] = { 0, Perl_magic_setenv, 0,
Perl_magic_clearenv, 0, 0, 0, 0 };

which mod_perl overrides in modperl_env.c (omitting copy/dup/local...):

static MGVTBL MP_vtbl_env = {0, modperl_env_magic_set_all, 0,
modperl_env_magic_clear_all, 0 };
static MGVTBL MP_vtbl_envelem = {0, modperl_env_magic_set, 0,
modperl_env_magic_clear, 0 };
StructCopy(&MP_vtbl_env, &PL_vtbl_env, MGVTBL);
StructCopy(&MP_vtbl_envelem, &PL_vtbl_envelem, MGVTBL);

It looks like Perl's magic uppercases %ENV keys, at least on creating
%ENV: On my system the output of 'set' (to show allow environment
variables) shows mixed case:

>set | findstr /i systemroot
SystemRoot=C:\Windows

but a Data::Dumper dump (at least) of %ENV shows uppercase:

>perl -MData::Dumper -le "print Dumper(\%ENV)" | findstr /i systemroot
        'SYSTEMROOT' => 'C:\\Windows',

The environment set up for mod_perl in ap_add_common_vars(), called
from modperl_env.c's modperl_env_request_populate(), explicitly sets
up SystemRoot (in mixed case):

env2env(e, "SystemRoot");

hence the variable appears in the original %ENV in mixed case. I'm
still not clear how the uppercase version appears after looking up the
mixed case version, though, especially since neither Perl's nor
mod_perl's magic vtable have 'get' fields anyway. I'm clearly missing
the piece of the puzzle that allows for case-insensitive lookups.

I see the same behaviour on the httpd24 branch, so it's not something
I've done in merging the threading branch into that. And I'd forgotten
that I also see the same behaviour on the trunk (with httpd-2.2.25)
too. I was sure that all tests passed on trunk, but this is all using
perl-5.19.5 rather than a stable 5.18.x, so presumably that's where
the trouble has crept in...

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@perl.apache.org
For additional commands, e-mail: dev-h...@perl.apache.org

Reply via email to