[PATCH] END blocks may segfault

Alex Hunsaker <[email protected]>
Newsgroups gmane.comp.apache.mod-perl
Message-ID <[email protected]>
Hi!

perl: 5.10.1, 5.12.1 (i686-linux, x86_64-linux)
mod_perl: 2.0.4

Basically if you have end blocks that modify/add END blocks things
might go crazy.

A simple test case for this is:
package test:
END { eval "END { }" for 1..10 }

gives:
Not a CODE reference.
END failed--call queue aborted.

if I add another END {}:
package test:
END { eval "END { }" for 1..10 }
END { }

I get:
Undefined subroutine &main:: called.
END failed--call queue aborted.

This was found as I was getting strange segfaults when trying to use
NYTProf.  Nicholas Clark was able to pinpoint the problem.

See:
http://groups.google.com/group/develnytprof-dev/msg/4ff26e6b3d95861f
thread: http://groups.google.com/group/develnytprof-dev/browse_thread/thread/20d2ea800e8936f

Ive included some relevant bits here (again from Nicholas):

> Of course, I looked at the core perl source to see how END blocks were run,
> and the behaviour was safe with perl. perl unshifts each CV from the list
> before it calls it. I should have remembered that inevitably mod_perl is
> "special".
>
> On reflection, I think that this *is* a bug in mod_perl, as they're going
> to get tripped up in similar fashion if any code run as part of an END block
> contains a string eval containing an END block.

Now the simple fix would be to just make modperl shift things off as
well (see attached patch to make it use Perl_call_list).  Course if
they use ModPerl::Global::special_list_(call|clear) like
t/modperl/endav.t things break.  As when we go to run END blocks or
call special_list_call()  they will have been shifted off.  This might
be acceptable behavior for END blocks, but I can see not wanting to
break other things that use modperl_perl_call_use.  Maybe, maybe not.
Thoughts?

Another option would be to copy/local() the array in
modpler_perl_call_list.  Of course that still wont get it "right"
because we wont run any newly defined subs... But at least we wont
segfault/crap out.

Thoughts?
modperl2_use_perl_call_list.patch (text/x-patch, 1 KB)
--- modperl_util.c.orig	2010-06-28 10:58:53.535686254 -0600
+++ modperl_util.c	2010-06-28 11:01:25.059112059 -0600
@@ -467,30 +467,12 @@
 
 void modperl_perl_call_list(pTHX_ AV *subs, const char *name)
 {
-    I32 i, oldscope = PL_scopestack_ix;
-    SV **ary = AvARRAY(subs);
-
     MP_TRACE_g(MP_FUNC, "pid %lu" MP_TRACEf_TID MP_TRACEf_PERLID
                " running %d %s subs",
                (unsigned long)getpid(), MP_TRACEv_TID_ MP_TRACEv_PERLID_
                AvFILLp(subs)+1, name);
 
-    for (i=0; i<=AvFILLp(subs); i++) {
-        CV *cv = (CV*)ary[i];
-        SV *atsv = ERRSV;
-
-        PUSHMARK(PL_stack_sp);
-        call_sv((SV*)cv, G_EVAL|G_DISCARD);
-
-        if (SvCUR(atsv)) {
-            Perl_sv_catpvf(aTHX_ atsv, "%s failed--call queue aborted",
-                           name);
-            while (PL_scopestack_ix > oldscope) {
-                LEAVE;
-            }
-            Perl_croak(aTHX_ "%s", SvPVX(atsv));
-        }
-    }
+    Perl_call_list(aTHX_ PL_scopestack_ix, subs);
 }
 
 void modperl_perl_exit(pTHX_ int status)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.