goto &Package::func destroying @_?!

M

Matthew Braid

Hi all,

Unfortunately this is another one that I can't reproduce in a small
script, but maybe the description will trigger something from someone....

In the system I'm writing library functions can be extended like so:

package Core;
use base qw/Exporter/;
{
no strict 'refs';
sub import { # This code severely chopped down to basics
# Redefine import so that overrides are noticed even
# in places where the original function has already been
# imported
my $class = shift;
my @funcs = @_;
my ($caller) = caller();
for my $f (@funcs) {
*{"$caller\::$f"} = sub {goto &{"$class\::$f"}};
}
}
}
sub foo {
print "Core::foo GOT (@_)\n";
}
# --- In a file not so very far away...
package Extension;
BEGIN {
require Core;
my $old = \&Core::foo;
sub foo {
print "Ext::foo GOT (@_)\n";
goto &$old;
}
*Core::foo = \&foo;
}

Of course, extensions can be extended etc etc. The problem I've run in
to is the goto bit - it seems that if the level of 'extension' is too
high, the destination of the goto ends up with @_ full of undefs - right
number of args, wrong values. Even stranger is that if I was expecting a
hashref keying some objects and I have:

$arg->{ObjectName}->method;

instead of the usual "Can't call method "method" on an undefined value"
error, the script is terminated with a signal 11.

Oddly enough, if I throw in the otherwise useless line:

@_ = @_;

just before the goto, suddenly it works again.

So there is a workaround - either the odd '@_ = @_' thing which looks
too much like a smiley or instead of goto& just simply call the old
function as in $old->(@_), but I'm thinking the destruction of @_ and
the terminate on signal 11 thing may be a bug in perl itself.

Any ideas?

MB
 
B

Brian McCauley

Matthew said:
Unfortunately this is another one that I can't reproduce in a small
script, but maybe the description will trigger something from someone....

It does.

In the last few weeks I've seen a post that shows that there does appear
to be a bug with the first element of @_ and goto.

Unfortunately having searched comp.lang.perl.* and PerlMonks I can't
locate it.
 
A

Anno Siegel

Matthew Braid said:
Hi all,

Unfortunately this is another one that I can't reproduce in a small
script, but maybe the description will trigger something from someone....

In the system I'm writing library functions can be extended like so:

package Core;
use base qw/Exporter/;

Why are you making Exporter a base class? You're not using it.
{
no strict 'refs';
sub import { # This code severely chopped down to basics
# Redefine import so that overrides are noticed even
# in places where the original function has already been
# imported
my $class = shift;
my @funcs = @_;
my ($caller) = caller();
for my $f (@funcs) {
*{"$caller\::$f"} = sub {goto &{"$class\::$f"}};

A sub that does nothing but "goto &foo" is equivalent to foo. As given,
you might as well say

*{"$caller\::$f"} = \ &{"$class\::$f"};
}
}
}
sub foo {
print "Core::foo GOT (@_)\n";
}
# --- In a file not so very far away...
package Extension;
BEGIN {
require Core;
my $old = \&Core::foo;
sub foo {
print "Ext::foo GOT (@_)\n";
goto &$old;
}
*Core::foo = \&foo;

Here you are changing the package Core. Normally an importing module
has no business doing that.
}

Of course, extensions can be extended etc etc. The problem I've run in
to is the goto bit - it seems that if the level of 'extension' is too

Which goto? There is one in Core and one in Extension.
high, the destination of the goto ends up with @_ full of undefs - right
number of args, wrong values.

How high is too high? With your code the arguments are handed down
just fine.
Even stranger is that if I was expecting a
hashref keying some objects and I have:

$arg->{ObjectName}->method;

instead of the usual "Can't call method "method" on an undefined value"
error, the script is terminated with a signal 11.

Signal numbers are system-dependent. Is that a SEGV?
Oddly enough, if I throw in the otherwise useless line:

@_ = @_;

just before the goto, suddenly it works again.

So there is a workaround - either the odd '@_ = @_' thing which looks
too much like a smiley or instead of goto& just simply call the old
function as in $old->(@_), but I'm thinking the destruction of @_ and
the terminate on signal 11 thing may be a bug in perl itself.

We (or anyone else concerned, like p5p) would have to see the effect.
Your code doesn't show it.

Anno
 
M

Matthew Braid

Anno said:
Why are you making Exporter a base class? You're not using it.

Hmm, good point - probably an artifact of development. In the original
code the 'Core' package uses another package as a base that has a custom
import function.
A sub that does nothing but "goto &foo" is equivalent to foo. As given,
you might as well say

*{"$caller\::$f"} = \ &{"$class\::$f"};

Not quite. In my way, if "$class\::$f" is overridden later to a new
function, the new function will be called even in packages where
"$class\::$f" has _already been imported_. The code below demonstrates this:

# START CODE
{
package Foo;
sub test {
print "FOO!\n";
}
}

{
package Bar;
*Bar::test = \&Foo::test; # Standard import
sub bartest {
print "BAR!\n";
test();
}
}
{
package Woo;
# V---- My import - changes will be noticed
BEGIN {*Woo::test = sub { goto &Foo::test }}
sub wootest {
print "WOO!\n";
test();
}
}

*test = \&Foo::test;
*bartest = \&Bar::bartest;
*wootest = \&Woo::wootest;
test(); # CALL 1
bartest(); # CALL 2
wootest(); # CALL 3
*Foo::test = sub { print "NEW FOO!\n" };
test(); # CALL 4
bartest(); # CALL 5
wootest(); # CALL 6
# END CODE

Which results in (comments added):

FOO! # CALL 1
BAR! # CALL 2
FOO!
WOO! # CALL 3
FOO!
FOO! # CALL 4 - changes not noticed
BAR! # CALL 5
FOO! # Hasn't noticed Foo::test has changed!
WOO! # CALL 6
NEW FOO! # _Has_ noticed Foo::test has changed!

Of course, in my actual code there wouldn't be three names - 'bartest'
and 'wootest' would all be called 'test' so the main script doesn't need
to know the new function names. Not usually what you want (which is why
Exporter does it your way) but in my case it is.
Here you are changing the package Core. Normally an importing module
has no business doing that.

True, but as I said the importing module is acting as a plugin that is
_supposed_ to override the 'Core'. Its whole purpose is to do 'extra
stuff' without the main script needing to do anything different. So
rather than the main script needing to be changed for every plugin, all
it needs to do is 'eval "require $extension"' (with error checking and
whatnot) - and then extensions can be defined in a config file.
Which goto? There is one in Core and one in Extension.

So far I've only run across this in the extensions. In the right
circumstances I guess the core goto's would also suffer the same effects
if it really is a problem with goto&.
How high is too high? With your code the arguments are handed down
just fine.

In my real code the level is 4 goto&'s. I know extending the test code I
posted does work - hence the first line of my post about it being one of
those annoying problems that I can't easily replicate. I spent a very
frustrating two hours trying to get it to happen in test code, and I
don't think my company would be too happy about me posting what is
technically their code to a newsgroup. It all boiled down to three
debugging lines:

print "EXT3: ABOUT TO GOTO EXT2::func - \@_ IS (@_)\n";
goto &Ext2::func;

#... in another package not so far away

package Ext2;
#....
sub func {
print "EXT2: ARRIVED AT EXT2::func - \@_ IS (@_)\n";
my ($href, @otherstuff) = @_;
print "EXT2::func: ABOUT TO USE KEY METHOD...\n";
$href->{KEY}->method();
print "EXT2::func: DONE!\n";
}

which resulted in:

EXT3: ABOUT TO GOTO EXT2::func - @_ IS (HASH(0x804d170) ARRAY(0x804d260) 3)
EXT2: ARRIVED AT EXT2::func - @_ IS ( )
EXT2::func: ABOUT TO USE KEY METHOD...
pid 37031 (perl), uid 303: exited on signal 11
Signal numbers are system-dependent. Is that a SEGV?

This is on FreeBSD, so yeah a segfault.
We (or anyone else concerned, like p5p) would have to see the effect.
Your code doesn't show it.

I'm trying :) Its the useless-use-of-@_=@_ that makes me think it must
be something happening between chained goto's - somehow the link to @_
is being weakened to a point where the next goto ends up pointing to the
wrong peice of memory and segfaults. Since including the broken @_ in a
string still 'works' (ie doesn't cause a segfault) I'm guessing maybe a
screwed up internal perl structure that can't be dereferenced but can be
stringified? The 'bad' @_ stringifies as if it was an array filled with
empty strings.

I wasn't posting this with the intention of someone being able to fix it
on this information - obviously its not enough. I was hoping someone
with a bigger perl head than me could see the situation and maybe give
me some tips on how to try and replicate it for further debugging. The
main code has been running fine for some time - it was just a new
extension that must have gone just over the line that suddenly threw
everything out.

MB
 
M

Matthew Braid

Brian said:
It does.

In the last few weeks I've seen a post that shows that there does appear
to be a bug with the first element of @_ and goto.

Unfortunately having searched comp.lang.perl.* and PerlMonks I can't
locate it.

Damn, well I'll keep looking. In my case it's not just the first element
though - I'm expecting to get a hashref, and arrayref and a scalar, and
for all three I get something that stringifies as '' and segfaults on
dereference.
 

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,779
Messages
2,569,606
Members
45,239
Latest member
Alex Young

Latest Threads

Top