Skip Menu |

This queue is for tickets about the mod_perl CPAN distribution.

Report information
The Basics
Id: 98750
Status: open
Priority: 0/
Queue: mod_perl

People
Owner: Nobody in particular
Requestors: mstock [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in:
  • 2.0.4
  • 2.0.7
  • 2.0.8
Fixed in: (no value)



Subject: Localizing $ENV{MOD_PERL} in perl-script may make $ENV{MOD_PERL} 'disappear' for subsequent requests
Given the attached EnvIssue.pm and the following Apache configuration: <Location /foo> SetHandler perl-script PerlResponseHandler EnvIssue </Location> When I access this location for the first time, I get output like this, which is what I would expect: PATH: $VAR1 = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'; $VAR1 = undef; $VAR1 = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'; MOD_PERL: $VAR1 = 'mod_perl/2.0.8'; $VAR1 = undef; $VAR1 = 'mod_perl/2.0.8'; However, on the second request to the same location (in the same process), I get this: PATH: $VAR1 = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'; $VAR1 = undef; $VAR1 = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'; MOD_PERL: $VAR1 = undef; $VAR1 = undef; $VAR1 = undef; So I'm doing the same for the PATH and MOD_PERL environment variables, but get different results. Adding PerlOptions -SetupEnv to the location helps, and I get the expected result. I first noticed this behavior in a setup with Plack::Handler::Apache2 (used for one application) and an internal framework which uses $ENV{MOD_PERL} to detect if it is running on mod_perl. Plack::Handler::Apache2 localizes $ENV{MOD_PERL} in its load_app() method, which, when combined with this (in my opinion buggy) behavior, resulted in seemingly random crashes of our applications. Using the above configuration and the example script, I can reproduce the behavior on Debian Wheezy (mod_perl 2.0.7, Apache 2.2.22, Perl v5.14.2), Debian Testing aka Jessie (mod_perl 2.0.8, Apache 2.4.10, Perl v5.20.0) and CentOS 5 (mod_perl 2.0.4, Apache 2.2.3, Perl v5.8.8).
Subject: EnvIssue.pm
package EnvIssue; use strict; use warnings; use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::Const -compile => qw(OK); use Data::Dumper; my @keys = qw(PATH MOD_PERL); sub handler { my $r = shift; $r->content_type('text/plain'); mp_env(); return Apache2::Const::OK; } sub mp_env { for my $key (@keys) { print $key.":\n"; print(Dumper($ENV{$key})); do { local $ENV{$key}; print(Dumper($ENV{$key})); }; print(Dumper($ENV{$key})); } return; } 1;
fix patch
Subject: modperl_env.patch
diff --git a/src/modules/perl/modperl_env.c b/src/modules/perl/modperl_env.c index 462b4b48..442488e8 100644 --- a/src/modules/perl/modperl_env.c +++ b/src/modules/perl/modperl_env.c @@ -84,6 +84,18 @@ static modperl_env_ent_t MP_env_const_vars[] = { { NULL } }; +int MP_env_const_vars_exists(const char *key) +{ + modperl_env_ent_t *ent = MP_env_const_vars; + while (ent->key) { + if (strncmp(key, ent->key, strlen(key)) == 0) { + return 1; + } + ent++; + } + return 0; +} + void modperl_env_hash_keys(pTHX) { modperl_env_ent_t *ent = MP_env_const_vars; @@ -550,8 +562,12 @@ static int modperl_env_magic_set(pTHX_ SV *sv, MAGIC *mg) { request_rec *r = (request_rec *)EnvMgObj; + MP_dENV_KEY; + if (MP_env_const_vars_exists(key)) { + return 0; + } + if (r) { - MP_dENV_KEY; MP_dENV_VAL; apr_table_set(r->subprocess_env, key, val); MP_TRACE_e(MP_FUNC, "[0x%lx] r->subprocess_env set: %s => %s", @@ -559,7 +575,6 @@ static int modperl_env_magic_set(pTHX_ SV *sv, MAGIC *mg) } else { #ifdef MP_TRACE - MP_dENV_KEY; MP_dENV_VAL; MP_TRACE_e(MP_FUNC, "[0x%lx] $ENV{%s} = \"%s\";",
add test
Subject: modperl_env_w_test.patch
diff --git a/ModPerl-Registry/t/cgi-bin/local_env.pl b/ModPerl-Registry/t/cgi-bin/local_env.pl new file mode 100644 index 00000000..710fd209 --- /dev/null +++ b/ModPerl-Registry/t/cgi-bin/local_env.pl @@ -0,0 +1,11 @@ +# please insert nothing before this line: -*- mode: cperl; cperl-indent-level: 4; cperl-continued-statement-offset: 4; indent-tabs-mode: nil -*- +# test env vars + +print "Content-type: text/plain\n\n"; +my $var = $ENV{QUERY_STRING}; +{ + local $ENV{$var}; +} +print exists $ENV{$var} && $ENV{$var}; + +__END__ diff --git a/ModPerl-Registry/t/local_env.t b/ModPerl-Registry/t/local_env.t new file mode 100644 index 00000000..32fb3503 --- /dev/null +++ b/ModPerl-Registry/t/local_env.t @@ -0,0 +1,31 @@ +# please insert nothing before this line: -*- mode: cperl; cperl-indent-level: 4; cperl-continued-statement-offset: 4; indent-tabs-mode: nil -*- +use strict; +use warnings FATAL => 'all'; + +use Apache::Test; +use Apache::TestUtil; +use Apache::TestRequest; +use Apache::TestConfig (); + +use Apache2::Build (); + +my $mpm_is_threaded = Apache2::Build->build_config->mpm_is_threaded(); + +my %modules = ( + registry => 'ModPerl::Registry', + perlrun => 'ModPerl::PerlRun', + registry_prefork => 'ModPerl::RegistryPrefork', + perlrun_prefork => 'ModPerl::PerlRunPrefork', +); + +my @aliases = sort keys %modules; + +plan tests => 2*@aliases, need 'mod_alias.c', + { "can't run under threaded MPMs" => !$mpm_is_threaded }; + +my $script = "local_env.pl"; +for my $alias (qw(registry_prefork perlrun_prefork registry perlrun)) { + my $url = "/$alias/$script?MOD_PERL_API_VERSION"; + ok t_cmp GET_BODY($url), '2'; + ok t_cmp GET_BODY($url), '2'; +} diff --git a/lib/Apache2/Build.pm b/lib/Apache2/Build.pm index 68ea07da..1d736b36 100644 --- a/lib/Apache2/Build.pm +++ b/lib/Apache2/Build.pm @@ -294,7 +294,7 @@ sub mpm_name { return $self->{mpm_name} if $self->{mpm_name}; if ($self->httpd_version =~ /^(\d+)\.(\d+)\.(\d+)/) { - delete $threaded_mpms{dynamic} if $self->mp_nonthreaded_ok; + delete $threaded_mpms{dynamic} if $self->mp_nonthreaded_ok || $self->mp_no_threads; return $self->{mpm_name} = 'dynamic' if ($1*1000+$2)*1000+$3>=2003000; } diff --git a/src/modules/perl/modperl_env.c b/src/modules/perl/modperl_env.c index 462b4b48..939cead3 100644 --- a/src/modules/perl/modperl_env.c +++ b/src/modules/perl/modperl_env.c @@ -84,6 +84,18 @@ static modperl_env_ent_t MP_env_const_vars[] = { { NULL } }; +int is_env_const_var(const char *key) +{ + modperl_env_ent_t *ent = MP_env_const_vars; + while (ent->key) { + if (strncmp(key, ent->key, strlen(key)) == 0) { + return 1; + } + ent++; + } + return 0; +} + void modperl_env_hash_keys(pTHX) { modperl_env_ent_t *ent = MP_env_const_vars; @@ -550,8 +562,12 @@ static int modperl_env_magic_set(pTHX_ SV *sv, MAGIC *mg) { request_rec *r = (request_rec *)EnvMgObj; + MP_dENV_KEY; + if (is_env_const_var(key)) { + return 0; + } + if (r) { - MP_dENV_KEY; MP_dENV_VAL; apr_table_set(r->subprocess_env, key, val); MP_TRACE_e(MP_FUNC, "[0x%lx] r->subprocess_env set: %s => %s", @@ -559,7 +575,6 @@ static int modperl_env_magic_set(pTHX_ SV *sv, MAGIC *mg) } else { #ifdef MP_TRACE - MP_dENV_KEY; MP_dENV_VAL; MP_TRACE_e(MP_FUNC, "[0x%lx] $ENV{%s} = \"%s\";",
first time PATH: $VAR1 = '/home/xxx/.rbenv/shims:/home/xxx/.rbenv/bin:/home/xxx/.rbenv/shims:/usr/local/bin:/usr/bin:/home/xxx/bin:/usr/local/sbin:/usr/sbin:/home/xxx/.local/bin:/home/xxx/bin'; $VAR1 = undef; $VAR1 = '/home/xxx/.rbenv/shims:/home/xxx/.rbenv/bin:/home/xxx/.rbenv/shims:/usr/local/bin:/usr/bin:/home/xxx/bin:/usr/local/sbin:/usr/sbin:/home/xxx/.local/bin:/home/xxx/bin'; MOD_PERL: $VAR1 = 'mod_perl/2.0.11-dev'; $VAR1 = undef; $VAR1 = 'mod_perl/2.0.11-dev'; second time PATH: $VAR1 = '/home/xxx/.rbenv/shims:/home/xxx/.rbenv/bin:/home/xxx/.rbenv/shims:/usr/local/bin:/usr/bin:/home/xxx/bin:/usr/local/sbin:/usr/sbin:/home/xxx/.local/bin:/home/xxx/bin'; $VAR1 = undef; $VAR1 = '/home/xxx/.rbenv/shims:/home/xxx/.rbenv/bin:/home/xxx/.rbenv/shims:/usr/local/bin:/usr/bin:/home/xxx/bin:/usr/local/sbin:/usr/sbin:/home/xxx/.local/bin:/home/xxx/bin'; MOD_PERL: $VAR1 = 'mod_perl/2.0.11-dev'; $VAR1 = undef; $VAR1 = 'mod_perl/2.0.11-dev';