Corion has asked for the wisdom of the Perl Monks concerning the following question:

I have the little program below (reduced somewhat from my last post) which dumps core. I'm not sure whether the use of Hook::LexWrap contributes to the problem, but I was too scared to try removing the glob/object trickery used by Hook::LexWrap.

The problem occurs with IndigoPerl 5.6.1, build 626, running under Windows 2000.

The Hook::LexWrap documentation states that @_ will be filled in the callback with the parameters to the original (wrapped) routine, plus an additional parameter which is the placeholder for the return value. So I'm expecting two elements in @_, first the passed parameter (bar in the example), and second either the place holder for my return value (undef on entry), or an element beyond the end of the array (undef as well).

As somebody who dosen't poke around in perls internals, my wild guess is that @_ in the "pre"-callback contains a (pointer to a) glob whose object has passed out of existence already, but that's a wild guess obviously.

Anybody wanting to hit me over the head with a P5P reference discussing this bug please feel free to do so :-).

Update: Updated the parameter to the call to wrapped_NoAttr() to reflect what the text says

#!/usr/bin/perl -w # Yes, I use a UNIX hashbang line, even though I'm running # under Windows. Call me weird. use strict; use warnings; use Hook::LexWrap; sub wrapClassMethod { my ($symbol) = @_; my $name = *{$symbol}{NAME}; #print "Wrapping $package" . "::" . "$name\n"; # Install our access level checker : wrap $name, pre => sub { # First I thought I was getting wrapClassMethod's @_, # but this isn't the case. It's getting curioser and # curioser. my ($first,@args) = @_; print "\$symbol here is $symbol\n"; $first = "<undef>" unless defined $first; print "\$first here is $first\n"; print "*** They are the same.\n" if $first eq $symbol +; print "They are not the same.\n" unless $first eq $sy +mbol; my $a; print "This works :"; $a = $_[0]; print "$a\n"; print "This dosen't work (core dump) :"; $a = $_[1]; print "$a\n"; }; } sub wrapped_NoAttr { print "foo\n"; }; wrapClassMethod(*wrapped_NoAttr); wrapped_NoAttr("bar");

perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web

Replies are listed 'Best First'.
Re: Bug ? Perl dumps core on reference to @_ ?
by TheDamian (Vicar) on Dec 02, 2001 at 05:10 UTC
    As somebody who dosen't poke around in perls internals, my wild guess is that @_ in the "pre"-callback contains a (pointer to a) glob whose object has passed out of existence already, but that's a wild guess obviously.

    In a "pre" callback, the last argument is really a reference to a Hook::LexWrap::Cleanup object (a blessed subroutine), which masquerades as undef when used as an rvalue.

    When $_[-1] is assigned to in a "pre" callback, this object loses its last reference, so its destructor is called, which invokes the advertised "short-circuiting" of the wrapped subroutine.

    Not having (or wanting!) access to a Windows machine, I can only guess that something in LexWrap is tripping a bug in the IndigoPerl core -- possibly something to do with destructor timing. :-(

      Your idea of wrong destructor timing made me take a second and deeper look at Hook::LexWrap (and some inserted print statements), and I could produce another core dumping script, which should trigger the same error as Hook::LexWrap with IndigoPerl :

      #!/usr/bin/perl -w use strict; use warnings; my @a = (); my $foo = bless \@a, 'Cleanup'; print $foo; package Cleanup; use overload q{""} => sub { undef }, #q{""} => sub { "foo" }, q{0+} => sub { undef }, q{bool} => sub { undef }; 1;

      It now seems to me as if the stringifying dosen't work correctly, because everything works fine if the second variant of stringifying (returning foo) is enabled. Destructors don't come into play, as I'm not defining any destructor anymore, it seems more like it's a stringify problem with classes that stringify to undef...

      perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: Bug ? Perl dumps core on reference to @_ ?
by Zaxo (Archbishop) on Dec 02, 2001 at 01:49 UTC
    Data point, it works on *nix ( ++ the shebang line!). I added a print scalar(@args)," \@args present.",$/; giving this output:
    $ ./CorionDump.pl $symbol here is *main::wrapped_NoAttr $first here is bar They are not the same. 1 @args present. This works :bar Use of uninitialized value in concatenation (.) at ./CorionDump.pl lin +e 33. This dosen't work (core dump) : foo $ ls CorionDump.pl $
    The placeholder behavior you describe is for post-wrappers. In a pre-wrapper assigning to $_[-1] triggers preemption, skipping to inner layers of wrappers IIUC.

    Hook::LexWrap appears to autovivify wrappers to undef in lines like:

    # Hook/LexWrap.pm:43 () = $wrapper{post}->(@_, $return) if $wrapper{post};
    I looks like if exists $wrapper{'post'}; should be preferred. Unfortunately, I don't use a recent enough AS installation to help with Windows specific problems, but I can imagine that undef coderefs might confuse it.

    After Compline,
    Zaxo

      Hook::LexWrap appears to autovivify wrappers to undef in lines like:
      # Hook/LexWrap.pm:43 () = $wrapper{post}->(@_, $return) if $wrapper{post};
      It looks like if exists $wrapper{'post'}; should be preferred.
      Perhaps from an aesthetic point-of-view, but it makes absolutely no difference in terms of behaviour. Testing $wrapper{'post'} in an if will not autovivify it. And even if it did, it would autovivify to undef, so the if would still fail, preventing the undefined value from ever actually being used as a subroutine reference.
      I can imagine that undef coderefs might confuse it.
      Quite probably. But only if they were actually ever called, which the if $wrapper{'post'}; ensures they never will be.