Perl hangs when returning lvalue closure from another lvalue closure

J

Julian Mehnle

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?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top