This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #68560] calling closure prototype SEGVs
authorFather Chrysostomos <sprout@cpan.org>
Tue, 30 Nov 2010 05:43:52 +0000 (21:43 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Tue, 30 Nov 2010 05:44:21 +0000 (21:44 -0800)
commit541ed3a941cdbe4a796e28c53e976cbcbbb3ccb7
tree644236ef4117ad0c5708c3162e6ce10879ff8cca
parent56a86867b86f603e24bea0daab37d0f2a978e03c
[perl #68560] calling closure prototype SEGVs

When a closure is created, the original sub is cloned (except that the
op tree is shared). That original sub (called the closure prototype)
is not usually accessible to perl.

An attribute handler (MODIFY_CODE_ATTRIBUTES) is passed a reference
to it, however. If that code reference is called within the attribute
handler, an ‘Undefined subroutine called’ error results, because the
op tree has not been attached yet.

If that code reference is stashed away and called after the attribute
handler returns, it will most likely crash.

This is because its pad is full of nulls.

A regular $proto->() or &$proto() call that sets up @_ will crash in
attempting to do so.

A &$proto call will bypass that, but attempting to read any lexical
variables from the containing scope will cause a crash. Any operator
that uses TARG (i.e., most of them) will crash.

So this commit puts a check for closure prototypes in pp_entersub. It
produces a new error message, ‘Closure prototype called’.

This does introduce a backward-incompatible change: code like this
used to work:

 sub MODIFY_CODE_ATTRIBUTES { $'proto = $_[1] }
 { my $x; () = sub :attr { () = $x; print "hello\n" } }
 &$'proto;

But writing a useful subroutine that tiptoes past the crashes is so
difficult that I think this breakage is acceptable.
pod/perldiag.pod
pp_hot.c
t/op/attrs.t