Skip Menu |

This queue is for tickets about the Moose CPAN distribution.

Report information
The Basics
Id: 85702
Status: open
Priority: 0/
Queue: Moose

People
Owner: Nobody in particular
Requestors: kain.winterheart [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Unimportant
Broken in: 2.0402
Fixed in: (no value)



Subject: virtual method + 'after' method modifier = deep recursion
Hello. I have following code: package asd; use Moose; sub init { } no Moose; package zxc; use Moose; extends 'asd'; sub init; after 'init' => sub { print "1\n"; }; no Moose; package main; zxc -> new() -> init(); ...and instead of getting this at composition time: The method 'init' was not found in the inheritance hierarchy for zxc at /usr/local/lib/perl/5.10.1/Class/MOP/Class.pm line 1053. Class::MOP::Class::__ANON__('Moose::Meta::Class=HASH(0x2785ef0)', 'init') called at /usr/local/lib/perl/5.10.1/Class/MOP/Class.pm line 1088 Class::MOP::Class::add_after_method_modifier('Moose::Meta::Class=HASH(0x2785ef0)', 'init', 'CODE(0x27836f0)') called at /usr/local/lib/perl/5.10.1/Moose/Util.pm line 267 Moose::Util::add_method_modifier('Moose::Meta::Class=HASH(0x2785ef0)', 'after', 'ARRAY(0x2630b40)') called at /usr/local/lib/perl/5.10.1/Moose.pm line 87 Moose::after(undef, 'init') called at /usr/local/lib/perl/5.10.1/Moose/Exporter.pm line 370 Moose::after('init', 'CODE(0x27836f0)') called at -e line 1 ...I'm getting this, and only when I'm calling init(): Deep recursion on subroutine "zxc::init" at /usr/local/lib/perl/5.10.1/Class/MOP/Method/Wrapped.pm line 56. Deep recursion on anonymous subroutine at /usr/local/lib/perl/5.10.1/Class/MOP/Method/Wrapped.pm line 91. . I know that my code won't work at all, but why can't the program just die at composition time instead of going into an infinite recursion? Could it be fixed somehow or is it already fixed in some new release? I'm using Moose 2.0402.
Subject: Re: [rt.cpan.org #85702] virtual method + 'after' method modifier = deep recursion
Date: Wed, 29 May 2013 07:52:44 -0700 (PDT)
To: "bug-Moose [...] rt.cpan.org" <bug-moose [...] rt.cpan.org>
From: "Chris Prather" <perigrin [...] prather.org>
doy can probabl correct me on this... but ...  ​It's my understanding that when you do: sub init; You're creating an empty slot in the stash that is different from a normal subref. Basically it is *not* equivalent to  ​sub init { }  ​  ​but rather similar to  *init{CODE} = undef;    So that when you do: after init => sub  { ... }; ​the coderef generated by the method modifer is *the only coderef* in the current stash. This means that when Moose goes to insert a reference to the wrapped method, it gets confused and creates a circular reference to the method-modifier. You've complicated this by also having a method in the parent class that is an *actual* subroutine. That means that Moose's normal checks against wrapping non-existant methods are circumvented. This is really an obscure edge case that depends on using broken / undefined behavior in Perl. You're right we should check for it, but I don't know how easy that would be to actually do. Can you create a failing test case? ​-Chris On Wed, May 29, 2013 at 10:42 AM, https://www.google.com/accounts/o8/id?id=AItOawmNaaaSXM6QuPiIhzjO159qgjtY8Hl P64 via RT <bug-Moose@rt.cpan.org> wrote: Show quoted text
> Wed May 29 10:42:57 2013: Request 85702 was acted upon. > Transaction: Ticket created by https://www.google.com/accounts/o8/id?id=AItOawmNaaaSXM6QuPiIhzjO159qgjtY8HlNP64 > Queue: Moose > Subject: virtual method + 'after' method modifier = deep recursion > Broken in: 2.0402 > Severity: Important > Owner: Nobody > Requestors: kain.winterheart@gmail.com > Status: new > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=85702 > > Hello. > I have following code: > package asd; > use Moose; > sub init > { > } > no Moose; > package zxc; > use Moose; > extends 'asd'; > sub init; > after 'init' => sub > { > print "1\n"; > }; > no Moose; > package main; > zxc -> new() -> init(); > ...and instead of getting this at composition time: > The method 'init' was not found in the inheritance hierarchy for zxc at /usr/local/lib/perl/5.10.1/Class/MOP/Class.pm line 1053. > Class::MOP::Class::__ANON__('Moose::Meta::Class=HASH(0x2785ef0)', 'init') called at /usr/local/lib/perl/5.10.1/Class/MOP/Class.pm line 1088 > Class::MOP::Class::add_after_method_modifier('Moose::Meta::Class=HASH(0x2785ef0)', 'init', 'CODE(0x27836f0)') called at /usr/local/lib/perl/5.10.1/Moose/Util.pm line 267 > Moose::Util::add_method_modifier('Moose::Meta::Class=HASH(0x2785ef0)', 'after', 'ARRAY(0x2630b40)') called at /usr/local/lib/perl/5.10.1/Moose.pm line 87 > Moose::after(undef, 'init') called at /usr/local/lib/perl/5.10.1/Moose/Exporter.pm line 370 > Moose::after('init', 'CODE(0x27836f0)') called at -e line 1 > ...I'm getting this, and only when I'm calling init(): > Deep recursion on subroutine "zxc::init" at /usr/local/lib/perl/5.10.1/Class/MOP/Method/Wrapped.pm line 56. > Deep recursion on anonymous subroutine at /usr/local/lib/perl/5.10.1/Class/MOP/Method/Wrapped.pm line 91. > . I know that my code won't work at all, but why can't the program just die at composition time instead of going into an infinite recursion? Could it be fixed somehow or is it already fixed in some new release? > I'm using Moose 2.0402.
From: kain.winterheart [...] gmail.com
I've attached test file, is it OK, or do you need something different? Срд Май 29 10:53:06 2013, perigrin@prather.org писал: Show quoted text
> doy can probabl correct me on this... but ...  > > > ​It's my understanding that when you do: > > > sub init; > > > You're creating an empty slot in the stash that is different from a > normal subref. Basically it is *not* equivalent to  > > > ​sub init { }  > ​  > > ​but rather similar to  > > > *init{CODE} = undef;  > >   > > So that when you do: > > > after init => sub  { ... }; > > > > ​the coderef generated by the method modifer is *the only coderef* in > the current stash. This means that when Moose goes to insert a > reference to the wrapped method, it gets confused and creates a > circular reference to the method-modifier. > > > You've complicated this by also having a method in the parent class > that is an *actual* subroutine. That means that Moose's normal > checks against wrapping non-existant methods are circumvented. > > > This is really an obscure edge case that depends on using broken / > undefined behavior in Perl. You're right we should check for it, > but I don't know how easy that would be to actually do. Can you > create a failing test case? > > > ​-Chris > > On Wed, May 29, 2013 at 10:42 AM, > https://www.google.com/accounts/o8/id?id=AItOawmNaaaSXM6QuPiIhzjO159qgjtY8Hl > P64 via RT <bug-Moose@rt.cpan.org> wrote: >
> > Wed May 29 10:42:57 2013: Request 85702 was acted upon. > > Transaction: Ticket created by
> https://www.google.com/accounts/o8/id?id=AItOawmNaaaSXM6QuPiIhzjO159qgjtY8HlNP64
> > Queue: Moose > > Subject: virtual method + 'after' method modifier = deep
> recursion
> > Broken in: 2.0402 > > Severity: Important > > Owner: Nobody > > Requestors: kain.winterheart@gmail.com > > Status: new > > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=85702 > > > Hello. > > I have following code: > > package asd; > > use Moose; > > sub init > > { > > } > > no Moose; > > package zxc; > > use Moose; > > extends 'asd'; > > sub init; > > after 'init' => sub > > { > > print "1\n"; > > }; > > no Moose; > > package main; > > zxc -> new() -> init(); > > ...and instead of getting this at composition time: > > The method 'init' was not found in the inheritance hierarchy for zxc
> at /usr/local/lib/perl/5.10.1/Class/MOP/Class.pm line 1053.
> >
> Class::MOP::Class::__ANON__('Moose::Meta::Class=HASH(0x2785ef0)', > 'init') called at /usr/local/lib/perl/5.10.1/Class/MOP/Class.pm > line 1088
> >
> Class::MOP::Class::add_after_method_modifier('Moose::Meta::Class=HASH(0x2785ef0)', > 'init', 'CODE(0x27836f0)') called at > /usr/local/lib/perl/5.10.1/Moose/Util.pm line 267
> >
> Moose::Util::add_method_modifier('Moose::Meta::Class=HASH(0x2785ef0)', > 'after', 'ARRAY(0x2630b40)') called at > /usr/local/lib/perl/5.10.1/Moose.pm line 87
> > Moose::after(undef, 'init') called at
> /usr/local/lib/perl/5.10.1/Moose/Exporter.pm line 370
> > Moose::after('init', 'CODE(0x27836f0)') called at -e line 1 > > ...I'm getting this, and only when I'm calling init(): > > Deep recursion on subroutine "zxc::init" at
> /usr/local/lib/perl/5.10.1/Class/MOP/Method/Wrapped.pm line 56.
> > Deep recursion on anonymous subroutine at
> /usr/local/lib/perl/5.10.1/Class/MOP/Method/Wrapped.pm line 91.
> > . I know that my code won't work at all, but why can't the program
> just die at composition time instead of going into an infinite > recursion? Could it be fixed somehow or is it already fixed in some > new release?
> > I'm using Moose 2.0402.
Subject: stub_subroutine_and_after_method_modifier_produces_deep_recursion.t
package Stub_subroutine_and_after_method_modifier_produces_deep_recursion::Class; use Moose; sub something; after 'something' => sub { }; no Moose; package Stub_subroutine_and_after_method_modifier_produces_deep_recursion; use Test::More tests => 1; { local $SIG{ 'ALRM' } = sub{ fail(); die; }; alarm 1; Stub_subroutine_and_after_method_modifier_produces_deep_recursion::Class -> new() -> something(); alarm 0; } ok( 1 );
Subject: Re: [rt.cpan.org #85702] virtual method + 'after' method modifier = deep recursion
Date: Thu, 30 May 2013 15:22:25 -0500
To: Chris Prather via RT <bug-Moose [...] rt.cpan.org>
From: Jesse Luehrs <doy [...] tozt.net>
On Wed, May 29, 2013 at 10:53:06AM -0400, Chris Prather via RT wrote: Show quoted text
> doy can probabl correct me on this... but ...  > > It's my understanding that when you do: > > sub init; > > You're creating an empty slot in the stash that is different from a > normal subref. Basically it is *not* equivalent to  > > sub init { }  > > but rather similar to  > > *init{CODE} = undef;  > > So that when you do: > > after init => sub  { ... }; > > the coderef generated by the method modifer is *the only coderef* in > the current stash. This means that when Moose goes to insert a > reference to the wrapped method, it gets confused and creates a > circular reference to the method-modifier.
Not quite, but close enough. Detecting stubs isn't hard (I think we may even have a method in the MOP for it already), and yeah, we should be checking that here. Method modifiers should just skip over stubs as if they weren't there when looking for a method to modify. -doy