As reported in other thread, I've seen mod_perl emit panic warnings such as the following ever since 5.19.7:
panic: attempt to copy freed scalar 7fb2264ffde0 to 7fb2264ffd08 at /Users/mschout/Sync/Apache-TryCatch/blib/lib/Apache/TryCatch.pm line 20. I've also seen random segementation faults caused by innocent looking "return" statements in a large code base. I've created a test mod perl handler that demonstrates this behaviour: ------------------ package Apache::TryCatch; use Apache2::Const -compile => qw(OK); use TryCatch; use CGI; sub handler :method { my ($self, $r) = @_; $r->content_type('text/plain'); print $self->crash($r); return Apache2::Const::OK; } sub crash { my $cgi = CGI->new; try { $cgi->param(x => 'x') } return "Hello World!"; } 1; ------------------ configured in httpd.conf as: PerlModule Apache::TryCatch PerlSwitches -I@ServerRoot/../lib <Location /crashme> SetHandler perl-script PerlResponseHandler Apache::TryCatch </Location> ------------------ Simply accessing /crashme causes a 500 internal server error and the panic warning in the httpd error log. I bisected against perl git, using mod_perl 2.0.9 and apache 2.2.29 as the mod_perl environment, and installing TryCatch from cpan, and discovered that the following perl commit is the culprit: > commit 437e3a7dac994ebace1195549170c81f474d9c20 > Author: Matthew Horsfall <wolfs...@gmail.com> > Date: Wed Dec 11 18:28:21 2013 -0500 > > Optimise out PUSHMARK/RETURN if return is the last statement in a sub. > > This makes: > > sub baz { return $cat; } > > Behave like: > > sub baz { $cat; } > > Which is notably faster. > > Unpatched: > > ./perl -Ilib/ ~/stuff/bench.pl > Benchmark: timing 40000000 iterations of normal, ret... > normal: 3 wallclock secs ( 1.60 usr + 0.01 sys = 1.61 CPU) @ > 24844720.50/s (n=40000000) > ret: 3 wallclock secs ( 2.08 usr + 0.00 sys = 2.08 CPU) @ > 19230769.23/s (n=40000000) > > Patched: > > ./perl -Ilib ~/stuff/bench.pl > Benchmark: timing 40000000 iterations of aret, normal... > normal: 2 wallclock secs ( 1.72 usr + 0.00 sys = 1.72 CPU) @ > 23255813.95/s (n=40000000) > ret: 2 wallclock secs ( 1.72 usr + 0.00 sys = 1.72 CPU) @ > 23255813.95/s (n=40000000) > > The difference in OP trees can be seen here: > > Unpatched: > > $ perl -MO=Concise,baz -e 'sub baz { return $cat }' > main::baz: > 5 <1> leavesub[1 ref] K/REFC,1 ->(end) > - <@> lineseq KP ->5 > 1 <;> nextstate(main 1 -e:1) v ->2 > 4 <@> return K ->5 > 2 <0> pushmark s ->3 > - <1> ex-rv2sv sK/1 ->4 > 3 <#> gvsv[*cat] s ->4 > -e syntax OK > > Patched: > > $ ./perl -Ilib -MO=Concise,baz -e 'sub baz { return $cat }' > main::baz: > 3 <1> leavesub[1 ref] K/REFC,1 ->(end) > - <@> lineseq KP ->3 > 1 <;> nextstate(main 1 -e:1) v ->2 > - <@> return K ->- > - <0> pushmark s ->2 > - <1> ex-rv2sv sK/1 ->- > 2 <$> gvsv(*cat) s ->3 > -e syntax OK > > (Includes some modifications from Steffen) > > ext/B/t/optree_samples.t | 18 +++++++++++++++++- > op.c | 31 +++++++++++++++++++++++++++++++ > op.h | 6 ++++++ > 3 files changed, 54 insertions(+), 1 deletion(-) Reverting the change to op.c completely fixes the problem. I cannot reproduce the panic after this change, and I do not get any segmentation faults either in a large codebase that I am also testing against. This problem seems to be mod_perl specific as the try { $cgi->param() } does not cause a panic when run outside of mod_perl. In addition, not all try { } blocks cause the panic. It seems that calling CGI.pm's param() method to set a value *does* cause it however. If anyone has any ideas on what might be causing behaviour in mod_perl, I'm all ears. I may try to dig into this, but I'm not familiar with mod_perl internals so that may take quite some time. Admittedly, TryCatch depends on Devel::Declare, which as I understand it makes changes to the optree at runtime. I'm guessing there is some interaction with the optree in mod_perl that TryCatch along with perl's optimization that removes the "return" ops that is causing this. I have put the test case as a module up on github so that anyone can clone it to reproduce the bug. The repository is here: https://github.com/mschout/modperl-trycatch-bug.git The readme explains how to run it, but essentially its install a perl >= 5.19.7, install mod_perl, install TryCatch, and then the usual "perl Makefile.PL && make test" Regards, Michael Schout