![]() |
Perl hangs when returning lvalue closure from another lvalue closure
Hi all,
I'm having a serious problem that using lvalue closures in a Perl class module causes Perl to hang. I have wasted days on researching the problem, but could not find a solution. I think it might be a bug in Perl; I'm using 5.8.0, but can reproduce the behavior on 5.6.1 as well. I failed to trim the scenario down to a pure sample program to demonstrate the bug, so I have to present you the whole thing (it's not that big, though): http://files.mehnle.net/tmp/perl-lvalue-closures/ -- or: -- http://files.mehnle.net/tmp/perl-lvalue-closures.tar.gz To execute the scenario, call "test.pl". The core is DBIx::Class, which is meant to transparently implement object persistency. USM::Class and USM::User are exemplary classes that are derived from DBIx::Class like this: DBIx::Class <-- USM::Class <-- USM::User Every class shall be able to have inheritable, overrideable class (not instance) fields, so I used the same mechanism Class::Data::Inheritable uses: For every class field, create a closure with its own field storage variable. If the closure is called from a derived class to modify the field value, it creates a new closure in the namespace of the derived class with its own field storage variable. It's supposed to work like this: DBIx::Class->foo('nil'); # DBIx::Class->foo eq 'nil' # USM::Class->foo eq 'nil' USM::Class->foo('zippo'); # DBIx::Class->foo eq 'nil' # USM::Class->foo eq 'zippo' Now I wanted to be clever and make these closures into lvalue subs to allow code like DBIx::Class->foo = 'nil'; USM::Class->foo = 'zippo'; See the class field accessor closure created by the _create_class_field sub in DBIx/Class.pm: 253: my $accessor = sub :lvalue { 254: my $want_class = shift(); 255: $want_class->_class_only(); 256: 257: no strict 'refs'; 258: 259: # Is field to be modified, and doesn't sub-class already have its # own accessor? 260: if (@_ and ($want_class ne $class)) { 261: # Create an accessor for sub-class, and return its $value as # an lvalue: 262: # $want_class->_create_class_field($field)->($want_class, @_); 263: my $acc = $want_class->_create_class_field($field); 264: $acc->($want_class, @_); 265: # $value; # DEBUG, this doesn't belong here! 266: } 267: else { 268: # We are a closure, so _create_class_field()'s $value is used 269: # for the field's storage: 270: $value = shift() if @_; 271: # Return $value as an lvalue: 272: $value; 273: } 274: }; To make a long story short, Perl hangs in in line 264, when calling the newly created accessor closure. If I insert a dummy lvalue after that call, like in line 265, then Perl does NOT hang, and returns from both the old and the newly created accessor successfully, although of course the wrong lvalue is then returned from the old accessor. Perl seems to hang in some kind of internal endless loop (100% CPU load), `strace` shows no more syscalls during the hang. Perl only terminates if I press <CTRL+C> eventually. I also tried debugging the thing in the Perl debugger, see "debug.log" for a debugger session log. Interestingly, manually performing the `$acc->($want_class, @_)` call (via the `x` debugger command when the debugger is in line 264) works. Though, as soon as the debugger does the call from the module's code, it hangs again. So all things considered, I guess the problem has to do with how Perl returns lvalues from lvalue subs. Any ideas? -- Julian Mehnle. |
| All times are GMT. The time now is 04:55 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.