Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Sub-Uplevel CPAN distribution.

Report information
The Basics
Id: 32335
Status: resolved
Priority: 0/
Queue: Sub-Uplevel

People
Owner: Nobody in particular
Requestors: abc159abc [...] hotmail.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: (no value)
Fixed in: (no value)



Subject: Problem when stacking calls to uplevel
Hello, I use perl v5.6.1 and Sub-Uplevel-0.18 under Windows XP sp2. When successive calls to uplevel are made, the _normal_caller is not called by _uplevel_caller with the good frame number. It returns the following errors when the caller() function is called: Use of uninitialized value in join or string at error_demo.pl line 45. Use of uninitialized value in join or string at error_demo.pl line 45. Use of uninitialized value in join or string at error_demo.pl line 45. This is due to line 189 where you compute the adjustment you'll use to go up in the stack. The problems comes from the fact that you sum all the offsets stored in @Up_Frames instead of just summing the differences between the offset of the current uplevel call and the offset of the next call. This causes the index $up to go out of bounds and makes the caller() function return undef. To fix this I propose you replace line 189 by: $adjust += 1 + abs((($saw_uplevel < scalar(@Up_Frames) - 1) ? $Up_Frames[$saw_uplevel + 1] : 0) - $Up_Frames[$saw_uplevel]) ; This compute the offset value as: offset = ((next element inboud) ? next element : 0) - current element I hope it is clear enough.
Subject: error_demo.pl
use strict; use warnings; use mod::test ; use Sub::Uplevel ; # subroutine A calls subroutine B with uplevel(), so when # subroutine B queries caller(), it gets main as the caller (just # like subroutine A) instead of getting subroutine A sub sub_a { warn "Entering Subroutine A\n" ; warn "caller() says: ", join(", ", (caller())[0 .. 2]), "\n\n\n" ; warn "Calling B\n" ; #~ sub_b(); uplevel 1, \&sub_b ; } sub sub_b { warn "Entering Subroutine B\n" ; warn "caller() says: ", join(", ", (caller())[0 .. 2]), "\n\n\n" ; warn "Calling C\n" ; sub_c(); #~ uplevel 2, \&sub_c ; } sub sub_c { warn "Entering Subroutine C\n" ; warn "caller() says: ", join(", ", (caller())[0 .. 2]), "\n\n\n" ; warn "Calling D with uplevel\n" ; uplevel 3, \&sub_d ; #~ sub_d() ; } sub sub_d { warn "Entering Subroutine D\n" ; warn "caller() says: ", join(", ", (caller())[0 .. 2]), "\n\n\n" ; } sub_a() ;
Subject: fixed_Uplevel.pm
package Sub::Uplevel; use strict; use vars qw($VERSION @ISA @EXPORT); $VERSION = '0.18'; # We must override *CORE::GLOBAL::caller if it hasn't already been # overridden or else Perl won't see our local override later. if ( not defined *CORE::GLOBAL::caller{CODE} ) { *CORE::GLOBAL::caller = \&_normal_caller; } require Exporter; @ISA = qw(Exporter); @EXPORT = qw(uplevel); =head1 NAME Sub::Uplevel - apparently run a function in a higher stack frame =head1 VERSION This documentation describes version 0.18 =head1 SYNOPSIS use Sub::Uplevel; sub foo { print join " - ", caller; } sub bar { uplevel 1, \&foo; } #line 11 bar(); # main - foo.plx - 11 =head1 DESCRIPTION Like Tcl's uplevel() function, but not quite so dangerous. The idea is just to fool caller(). All the really naughty bits of Tcl's uplevel() are avoided. B<THIS IS NOT THE SORT OF THING YOU WANT TO DO EVERYDAY> =over 4 =item B<uplevel> uplevel $num_frames, \&func, @args; Makes the given function think it's being executed $num_frames higher than the current stack level. So when they use caller($frames) it will actually give caller($frames + $num_frames) for them. C<uplevel(1, \&some_func, @_)> is effectively C<goto &some_func> but you don't immediately exit the current subroutine. So while you can't do this: sub wrapper { print "Before\n"; goto &some_func; print "After\n"; } you can do this: sub wrapper { print "Before\n"; my @out = uplevel 1, &some_func; print "After\n"; return @out; } =cut use vars qw/@Up_Frames $Caller_Proxy/; # @Up_Frames -- uplevel stack # $Caller_Proxy -- whatever caller() override was in effect before uplevel sub uplevel { my($num_frames, $func, @args) = @_; local @Up_Frames = ($num_frames, @Up_Frames ); # backwards compatible version of "no warnings 'redefine'" my $old_W = $^W; $^W = 0; # Update the caller proxy if the uplevel override isn't in effect local $Caller_Proxy = *CORE::GLOBAL::caller{CODE} if *CORE::GLOBAL::caller{CODE} != \&_uplevel_caller; local *CORE::GLOBAL::caller = \&_uplevel_caller; # restore old warnings state $^W = $old_W; return $func->(@args); } sub _normal_caller (;$) { my $height = $_[0]; $height++; if( wantarray and !@_ ) { return (CORE::caller($height))[0..2]; } else { return CORE::caller($height); } } sub _uplevel_caller (;$) { my $height = $_[0] || 0; # shortcut if no uplevels have been called # always add +1 to CORE::caller (proxy caller function) # to skip this function's caller return $Caller_Proxy->( $height + 1 ) if ! @Up_Frames; =begin _private So it has to work like this: Call stack Actual uplevel 1 CORE::GLOBAL::caller Carp::short_error_loc 0 Carp::shortmess_heavy 1 0 Carp::croak 2 1 try_croak 3 2 uplevel 4 function_that_called_uplevel 5 caller_we_want_to_see 6 3 its_caller 7 4 So when caller(X) winds up below uplevel(), it only has to use CORE::caller(X+1) (to skip CORE::GLOBAL::caller). But when caller(X) winds up no or above uplevel(), it's CORE::caller(X+1+uplevel+1). Which means I'm probably going to have to do something nasty like walk up the call stack on each caller() to see if I'm going to wind up before or after Sub::Uplevel::uplevel(). =end _private =begin _dagolden I found the description above a bit confusing. Instead, this is the logic that I found clearer when CORE::GLOBAL::caller is invoked and we have to walk up the call stack: * if searching up to the requested height in the real call stack doesn't find a call to uplevel, then we can return the result at that height in the call stack * if we find a call to uplevel, we need to keep searching upwards beyond the requested height at least by the amount of upleveling requested for that call to uplevel (from the Up_Frames stack set during the uplevel call) * additionally, we need to hide the uplevel subroutine call, too, so we search upwards one more level for each call to uplevel * when we've reached the top of the search, we want to return that frame in the call stack, i.e. the requested height plus any uplevel adjustments found during the search =end _dagolden =cut my $saw_uplevel = 0; my $adjust = 0; # walk up the call stack to fight the right package level to return; # look one higher than requested for each call to uplevel found # and adjust by the amount found in the Up_Frames stack for that call. # We *must* use CORE::caller here since we need the real stack not what # some other override says the stack looks like, just in case that other # override breaks things in some horrible way for ( my $up = 0; $up <= $height + $adjust; $up++ ) { my @caller = CORE::caller($up + 1); if( defined $caller[0] && $caller[0] eq __PACKAGE__ ) { # add one for each uplevel call seen # and look into the uplevel stack for the offset #~ $adjust += 1 + $Up_Frames[$saw_uplevel]; $adjust += 1 + abs((($saw_uplevel < scalar(@Up_Frames) - 1) ? $Up_Frames[$saw_uplevel + 1] : 0) - $Up_Frames[$saw_uplevel]) ; $saw_uplevel++; } } # For returning values, we pass through the call to the proxy caller # function, just at a higher stack level my @caller = $Caller_Proxy->($height + $adjust + 1); if( wantarray ) { if( !@_ ) { @caller = @caller[0..2]; } return @caller; } else { return $caller[0]; } } =back =head1 EXAMPLE The main reason I wrote this module is so I could write wrappers around functions and they wouldn't be aware they've been wrapped. use Sub::Uplevel; my $original_foo = \&foo; *foo = sub { my @output = uplevel 1, $original_foo; print "foo() returned: @output"; return @output; }; If this code frightens you B<you should not use this module.> =head1 BUGS and CAVEATS Well, the bad news is uplevel() is about 5 times slower than a normal function call. XS implementation anyone? Sub::Uplevel overrides CORE::GLOBAL::caller temporarily for the scope of each uplevel call. It does its best to work with any previously existing CORE::GLOBAL::caller (both when Sub::Uplevel is first loaded and within each uplevel call) such as from Contextual::Return or Hook::LexWrap. However, if you are routinely using multiple modules that override CORE::GLOBAL::caller, you are probably asking for trouble. =head1 HISTORY Those who do not learn from HISTORY are doomed to repeat it. The lesson here is simple: Don't sit next to a Tcl programmer at the dinner table. =head1 THANKS Thanks to Brent Welch, Damian Conway and Robin Houston. =head1 AUTHORS David A Golden E<lt>dagolden@cpan.orgE<gt> (current maintainer) Michael G Schwern E<lt>schwern@pobox.comE<gt> (original author) =head1 LICENSE Original code Copyright (c) 2001 to 2007 by Michael G Schwern. Additional code Copyright (c) 2006 to 2007 by David A Golden. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html =head1 SEE ALSO PadWalker (for the similar idea with lexicals), Hook::LexWrap, Tcl's uplevel() at http://www.scriptics.com/man/tcl8.4/TclCmd/uplevel.htm =cut 1;
Subject: Re: [rt.cpan.org #32335] Problem when stacking calls to uplevel
Date: Tue, 15 Jan 2008 15:55:40 -0500
To: bug-Sub-Uplevel [...] rt.cpan.org
From: "David Golden" <dagolden [...] cpan.org>
Show quoted text
> The problems comes from the fact that you sum all the offsets stored in > @Up_Frames instead of just summing the differences between the offset of > the current uplevel call and the offset of the next call. This causes > the index $up to go out of bounds and makes the caller() function return > undef. > > To fix this I propose you replace line 189 by: > $adjust += 1 + abs((($saw_uplevel < scalar(@Up_Frames) - 1) ? > $Up_Frames[$saw_uplevel + 1] : 0) - $Up_Frames[$saw_uplevel]) ; > > This compute the offset value as: > offset = ((next element inboud) ? next element : 0) - current element > > I hope it is clear enough.
Thank you very much for the bug report -- particularly with the demo file. I'll take a look and make sure I understand the fix. (Every time I work I Sub::Uplevel it takes me a bit to figure out again what's going on -- nested uplevels were tricky in the first place.) On the surface, it seems to make sense. David
Subject: Re: [rt.cpan.org #32335] Problem when stacking calls to uplevel
Date: Tue, 15 Jan 2008 16:55:02 -0500
To: bug-Sub-Uplevel [...] rt.cpan.org
From: "David Golden" <dagolden [...] cpan.org>
On Jan 15, 2008 1:43 PM, vive via RT <bug-Sub-Uplevel@rt.cpan.org> wrote: Show quoted text
> It returns the following errors when the caller() function is called: > Use of uninitialized value in join or string at error_demo.pl line 45. > Use of uninitialized value in join or string at error_demo.pl line 45. > Use of uninitialized value in join or string at error_demo.pl line 45.
I've looked more closely at this and I don't think it's a bug. Your demo program calls uplevel 3 when the apparent call stack isn't that deep (taking into account the prior uplevel call, which hides subroutine B). Therefore, you get undefined from caller(). Maybe uplevel should warn if someone attempts to call uplevel for more than the height of the apparent call stack. Here's a revised version of your demo program that shows what's happening. I use "cluck" to show the stack trace. Notice after entering subroutine C, the uplevel call of 3 happens when the call stack only has two entries. If you change the uplevel in C to 2, it works fine. If I'm missing something, please let me know. I'm not sure why you think that the uplevel of 3 in that situation shouldn't give undef. David

Message body is not shown because sender requested not to inline it.

From: abc159abc [...] hotmail.com
On Tue Jan 15 16:55:20 2008, DAGOLDEN wrote: Show quoted text
> On Jan 15, 2008 1:43 PM, vive via RT <bug-Sub-Uplevel@rt.cpan.org> wrote:
> > It returns the following errors when the caller() function is called: > > Use of uninitialized value in join or string at error_demo.pl line 45. > > Use of uninitialized value in join or string at error_demo.pl line 45. > > Use of uninitialized value in join or string at error_demo.pl line 45.
> > I've looked more closely at this and I don't think it's a bug. Your > demo program calls uplevel 3 when the apparent call stack isn't that > deep (taking into account the prior uplevel call, which hides > subroutine B). Therefore, you get undefined from caller(). > > Maybe uplevel should warn if someone attempts to call uplevel for more > than the height of the apparent call stack. > > Here's a revised version of your demo program that shows what's > happening. I use "cluck" to show the stack trace. Notice after > entering subroutine C, the uplevel call of 3 happens when the call > stack only has two entries. If you change the uplevel in C to 2, it > works fine. > > If I'm missing something, please let me know. I'm not sure why you > think that the uplevel of 3 in that situation shouldn't give undef. > > David
Hello, I tried you code with the original library and with the fixed library (I just added a caller in each function to see the same output as in my initial code). Here is the original output: Show quoted text
>perl error_demo_stack.pl
Entering Subroutine A Calling B with uplevel 1 at error_demo_stack.pl line 16 main::sub_a() called at error_demo_stack.pl line 54 caller() says: main, error_demo_stack.pl, 54 Entering Subroutine B Calling C at error_demo_stack.pl line 26 main::sub_a() called at error_demo_stack.pl line 54 caller() says: main, error_demo_stack.pl, 54 Entering Subroutine C Calling D with uplevel 3 at error_demo_stack.pl line 37 main::sub_c() called at error_demo_stack.pl line 30 main::sub_a() called at error_demo_stack.pl line 54 caller() says: main, error_demo_stack.pl, 30 Entering Subroutine D Inside D at error_demo_stack.pl line 48 caller() says: undef, undef, undef You can see that the last call to caller returns undef. However the call stack is: main 4-> sub_a 3-> (uplevel(1) -> sub_b) 2-> sub_c 1-> (uplevel(3) -> sub_d) (We see 4 levels but in fact we have 7 levels) So if I say uplevel 3, \&sub_d context should be main. It looks like the call stack is not deep because we called uplevel. If we hadn't we would have had a longer stack. Here is what the fixed library returns: Show quoted text
>perl error_call.pl
Entering Subroutine A Calling B with uplevel 1 at error_call.pl line 16 main::sub_a() called at error_call.pl line 54 caller() says: main, error_call.pl, 54 Entering Subroutine B Calling C at error_call.pl line 26 main::sub_a() called at error_call.pl line 54 caller() says: main, error_call.pl, 54 Entering Subroutine C Calling D with uplevel 3 at error_call.pl line 37 main::sub_c() called at error_call.pl line 30 main::sub_a() called at error_call.pl line 54 caller() says: main, error_call.pl, 30 Entering Subroutine D Inside D at error_call.pl line 48 main::sub_a() called at error_call.pl line 54 caller() says: main, error_call.pl, 54 This exactly reflects the call stack I think we should have. main 4-> sub_a 3-> (uplevel(1) -> sub_b) 2-> sub_c 1-> (uplevel(3) -> sub_d) If I call uplevel 3 i want my context to be 3 levels above my caller which is main in sub_d. Don't you think ?
use strict; use warnings; #use mod::test ; use Carp qw/cluck/; use Sub::Uplevel ; # subroutine A calls subroutine B with uplevel(), so when # subroutine B queries caller(), it gets main as the caller (just # like subroutine A) instead of getting subroutine A sub sub_a { my $uplevel = 1; warn "\nEntering Subroutine A\n" ; cluck "Calling B with uplevel $uplevel" ; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; uplevel $uplevel, \&sub_b ; } sub sub_b { warn "\nEntering Subroutine B\n" ; cluck "Calling C" ; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; sub_c(); } sub sub_c { my $uplevel = 3; warn "\nEntering Subroutine C\n" ; cluck "Calling D with uplevel $uplevel" ; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; uplevel $uplevel, \&sub_d ; } sub sub_d { warn "\nEntering Subroutine D\n" ; cluck "Inside D"; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; } sub_a() ;
package Sub::Uplevel; use strict; use vars qw($VERSION @ISA @EXPORT); $VERSION = '0.18'; # We must override *CORE::GLOBAL::caller if it hasn't already been # overridden or else Perl won't see our local override later. if ( not defined *CORE::GLOBAL::caller{CODE} ) { *CORE::GLOBAL::caller = \&_normal_caller; } require Exporter; @ISA = qw(Exporter); @EXPORT = qw(uplevel); =head1 NAME Sub::Uplevel - apparently run a function in a higher stack frame =head1 VERSION This documentation describes version 0.18 =head1 SYNOPSIS use Sub::Uplevel; sub foo { print join " - ", caller; } sub bar { uplevel 1, \&foo; } #line 11 bar(); # main - foo.plx - 11 =head1 DESCRIPTION Like Tcl's uplevel() function, but not quite so dangerous. The idea is just to fool caller(). All the really naughty bits of Tcl's uplevel() are avoided. B<THIS IS NOT THE SORT OF THING YOU WANT TO DO EVERYDAY> =over 4 =item B<uplevel> uplevel $num_frames, \&func, @args; Makes the given function think it's being executed $num_frames higher than the current stack level. So when they use caller($frames) it will actually give caller($frames + $num_frames) for them. C<uplevel(1, \&some_func, @_)> is effectively C<goto &some_func> but you don't immediately exit the current subroutine. So while you can't do this: sub wrapper { print "Before\n"; goto &some_func; print "After\n"; } you can do this: sub wrapper { print "Before\n"; my @out = uplevel 1, &some_func; print "After\n"; return @out; } =cut use vars qw/@Up_Frames $Caller_Proxy/; # @Up_Frames -- uplevel stack # $Caller_Proxy -- whatever caller() override was in effect before uplevel sub uplevel { my($num_frames, $func, @args) = @_; local @Up_Frames = ($num_frames, @Up_Frames ); # backwards compatible version of "no warnings 'redefine'" my $old_W = $^W; $^W = 0; # Update the caller proxy if the uplevel override isn't in effect local $Caller_Proxy = *CORE::GLOBAL::caller{CODE} if *CORE::GLOBAL::caller{CODE} != \&_uplevel_caller; local *CORE::GLOBAL::caller = \&_uplevel_caller; # restore old warnings state $^W = $old_W; return $func->(@args); } sub _normal_caller (;$) { my $height = $_[0]; $height++; if( wantarray and !@_ ) { return (CORE::caller($height))[0..2]; } else { return CORE::caller($height); } } sub _uplevel_caller (;$) { my $height = $_[0] || 0; # shortcut if no uplevels have been called # always add +1 to CORE::caller (proxy caller function) # to skip this function's caller return $Caller_Proxy->( $height + 1 ) if ! @Up_Frames; =begin _private So it has to work like this: Call stack Actual uplevel 1 CORE::GLOBAL::caller Carp::short_error_loc 0 Carp::shortmess_heavy 1 0 Carp::croak 2 1 try_croak 3 2 uplevel 4 function_that_called_uplevel 5 caller_we_want_to_see 6 3 its_caller 7 4 So when caller(X) winds up below uplevel(), it only has to use CORE::caller(X+1) (to skip CORE::GLOBAL::caller). But when caller(X) winds up no or above uplevel(), it's CORE::caller(X+1+uplevel+1). Which means I'm probably going to have to do something nasty like walk up the call stack on each caller() to see if I'm going to wind up before or after Sub::Uplevel::uplevel(). =end _private =begin _dagolden I found the description above a bit confusing. Instead, this is the logic that I found clearer when CORE::GLOBAL::caller is invoked and we have to walk up the call stack: * if searching up to the requested height in the real call stack doesn't find a call to uplevel, then we can return the result at that height in the call stack * if we find a call to uplevel, we need to keep searching upwards beyond the requested height at least by the amount of upleveling requested for that call to uplevel (from the Up_Frames stack set during the uplevel call) * additionally, we need to hide the uplevel subroutine call, too, so we search upwards one more level for each call to uplevel * when we've reached the top of the search, we want to return that frame in the call stack, i.e. the requested height plus any uplevel adjustments found during the search =end _dagolden =cut my $saw_uplevel = 0; my $adjust = 0; # walk up the call stack to fight the right package level to return; # look one higher than requested for each call to uplevel found # and adjust by the amount found in the Up_Frames stack for that call. # We *must* use CORE::caller here since we need the real stack not what # some other override says the stack looks like, just in case that other # override breaks things in some horrible way for ( my $up = 0; $up <= $height + $adjust; $up++ ) { my @caller = CORE::caller($up + 1); if( defined $caller[0] && $caller[0] eq __PACKAGE__ ) { # add one for each uplevel call seen # and look into the uplevel stack for the offset $adjust += 1 + $Up_Frames[$saw_uplevel]; $saw_uplevel++; } } # For returning values, we pass through the call to the proxy caller # function, just at a higher stack level my @caller = $Caller_Proxy->($height + $adjust + 1); if( wantarray ) { if( !@_ ) { @caller = @caller[0..2]; } return @caller; } else { return $caller[0]; } } =back =head1 EXAMPLE The main reason I wrote this module is so I could write wrappers around functions and they wouldn't be aware they've been wrapped. use Sub::Uplevel; my $original_foo = \&foo; *foo = sub { my @output = uplevel 1, $original_foo; print "foo() returned: @output"; return @output; }; If this code frightens you B<you should not use this module.> =head1 BUGS and CAVEATS Well, the bad news is uplevel() is about 5 times slower than a normal function call. XS implementation anyone? Sub::Uplevel overrides CORE::GLOBAL::caller temporarily for the scope of each uplevel call. It does its best to work with any previously existing CORE::GLOBAL::caller (both when Sub::Uplevel is first loaded and within each uplevel call) such as from Contextual::Return or Hook::LexWrap. However, if you are routinely using multiple modules that override CORE::GLOBAL::caller, you are probably asking for trouble. =head1 HISTORY Those who do not learn from HISTORY are doomed to repeat it. The lesson here is simple: Don't sit next to a Tcl programmer at the dinner table. =head1 THANKS Thanks to Brent Welch, Damian Conway and Robin Houston. =head1 AUTHORS David A Golden E<lt>dagolden@cpan.orgE<gt> (current maintainer) Michael G Schwern E<lt>schwern@pobox.comE<gt> (original author) =head1 LICENSE Original code Copyright (c) 2001 to 2007 by Michael G Schwern. Additional code Copyright (c) 2006 to 2007 by David A Golden. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html =head1 SEE ALSO PadWalker (for the similar idea with lexicals), Hook::LexWrap, Tcl's uplevel() at http://www.scriptics.com/man/tcl8.4/TclCmd/uplevel.htm =cut 1;
package Sub::UplevelFix; use strict; use vars qw($VERSION @ISA @EXPORT); $VERSION = '0.18'; # We must override *CORE::GLOBAL::caller if it hasn't already been # overridden or else Perl won't see our local override later. if ( not defined *CORE::GLOBAL::caller{CODE} ) { *CORE::GLOBAL::caller = \&_normal_caller; } require Exporter; @ISA = qw(Exporter); @EXPORT = qw(uplevel); =head1 NAME Sub::Uplevel - apparently run a function in a higher stack frame =head1 VERSION This documentation describes version 0.18 =head1 SYNOPSIS use Sub::Uplevel; sub foo { print join " - ", caller; } sub bar { uplevel 1, \&foo; } #line 11 bar(); # main - foo.plx - 11 =head1 DESCRIPTION Like Tcl's uplevel() function, but not quite so dangerous. The idea is just to fool caller(). All the really naughty bits of Tcl's uplevel() are avoided. B<THIS IS NOT THE SORT OF THING YOU WANT TO DO EVERYDAY> =over 4 =item B<uplevel> uplevel $num_frames, \&func, @args; Makes the given function think it's being executed $num_frames higher than the current stack level. So when they use caller($frames) it will actually give caller($frames + $num_frames) for them. C<uplevel(1, \&some_func, @_)> is effectively C<goto &some_func> but you don't immediately exit the current subroutine. So while you can't do this: sub wrapper { print "Before\n"; goto &some_func; print "After\n"; } you can do this: sub wrapper { print "Before\n"; my @out = uplevel 1, &some_func; print "After\n"; return @out; } =cut use vars qw/@Up_Frames $Caller_Proxy/; # @Up_Frames -- uplevel stack # $Caller_Proxy -- whatever caller() override was in effect before uplevel sub uplevel { my($num_frames, $func, @args) = @_; local @Up_Frames = ($num_frames, @Up_Frames ); # backwards compatible version of "no warnings 'redefine'" my $old_W = $^W; $^W = 0; # Update the caller proxy if the uplevel override isn't in effect local $Caller_Proxy = *CORE::GLOBAL::caller{CODE} if *CORE::GLOBAL::caller{CODE} != \&_uplevel_caller; local *CORE::GLOBAL::caller = \&_uplevel_caller; # restore old warnings state $^W = $old_W; return $func->(@args); } sub _normal_caller (;$) { my $height = $_[0]; $height++; if( wantarray and !@_ ) { return (CORE::caller($height))[0..2]; } else { return CORE::caller($height); } } sub _uplevel_caller (;$) { my $height = $_[0] || 0; # shortcut if no uplevels have been called # always add +1 to CORE::caller (proxy caller function) # to skip this function's caller return $Caller_Proxy->( $height + 1 ) if ! @Up_Frames; =begin _private So it has to work like this: Call stack Actual uplevel 1 CORE::GLOBAL::caller Carp::short_error_loc 0 Carp::shortmess_heavy 1 0 Carp::croak 2 1 try_croak 3 2 uplevel 4 function_that_called_uplevel 5 caller_we_want_to_see 6 3 its_caller 7 4 So when caller(X) winds up below uplevel(), it only has to use CORE::caller(X+1) (to skip CORE::GLOBAL::caller). But when caller(X) winds up no or above uplevel(), it's CORE::caller(X+1+uplevel+1). Which means I'm probably going to have to do something nasty like walk up the call stack on each caller() to see if I'm going to wind up before or after Sub::Uplevel::uplevel(). =end _private =begin _dagolden I found the description above a bit confusing. Instead, this is the logic that I found clearer when CORE::GLOBAL::caller is invoked and we have to walk up the call stack: * if searching up to the requested height in the real call stack doesn't find a call to uplevel, then we can return the result at that height in the call stack * if we find a call to uplevel, we need to keep searching upwards beyond the requested height at least by the amount of upleveling requested for that call to uplevel (from the Up_Frames stack set during the uplevel call) * additionally, we need to hide the uplevel subroutine call, too, so we search upwards one more level for each call to uplevel * when we've reached the top of the search, we want to return that frame in the call stack, i.e. the requested height plus any uplevel adjustments found during the search =end _dagolden =cut my $saw_uplevel = 0; my $adjust = 0; # walk up the call stack to fight the right package level to return; # look one higher than requested for each call to uplevel found # and adjust by the amount found in the Up_Frames stack for that call. # We *must* use CORE::caller here since we need the real stack not what # some other override says the stack looks like, just in case that other # override breaks things in some horrible way for ( my $up = 0; $up <= $height + $adjust; $up++ ) { my @caller = CORE::caller($up + 1); if( defined $caller[0] && $caller[0] eq __PACKAGE__ ) { # add one for each uplevel call seen # and look into the uplevel stack for the offset #~ $adjust += 1 + $Up_Frames[$saw_uplevel]; $adjust += 1 + abs((($saw_uplevel < scalar(@Up_Frames) - 1) ? $Up_Frames[$saw_uplevel + 1] : 0) - $Up_Frames[$saw_uplevel]) ; $saw_uplevel++; } } # For returning values, we pass through the call to the proxy caller # function, just at a higher stack level my @caller = $Caller_Proxy->($height + $adjust + 1); if( wantarray ) { if( !@_ ) { @caller = @caller[0..2]; } return @caller; } else { return $caller[0]; } } =back =head1 EXAMPLE The main reason I wrote this module is so I could write wrappers around functions and they wouldn't be aware they've been wrapped. use Sub::Uplevel; my $original_foo = \&foo; *foo = sub { my @output = uplevel 1, $original_foo; print "foo() returned: @output"; return @output; }; If this code frightens you B<you should not use this module.> =head1 BUGS and CAVEATS Well, the bad news is uplevel() is about 5 times slower than a normal function call. XS implementation anyone? Sub::Uplevel overrides CORE::GLOBAL::caller temporarily for the scope of each uplevel call. It does its best to work with any previously existing CORE::GLOBAL::caller (both when Sub::Uplevel is first loaded and within each uplevel call) such as from Contextual::Return or Hook::LexWrap. However, if you are routinely using multiple modules that override CORE::GLOBAL::caller, you are probably asking for trouble. =head1 HISTORY Those who do not learn from HISTORY are doomed to repeat it. The lesson here is simple: Don't sit next to a Tcl programmer at the dinner table. =head1 THANKS Thanks to Brent Welch, Damian Conway and Robin Houston. =head1 AUTHORS David A Golden E<lt>dagolden@cpan.orgE<gt> (current maintainer) Michael G Schwern E<lt>schwern@pobox.comE<gt> (original author) =head1 LICENSE Original code Copyright (c) 2001 to 2007 by Michael G Schwern. Additional code Copyright (c) 2006 to 2007 by David A Golden. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html =head1 SEE ALSO PadWalker (for the similar idea with lexicals), Hook::LexWrap, Tcl's uplevel() at http://www.scriptics.com/man/tcl8.4/TclCmd/uplevel.htm =cut 1;
use strict; use warnings; #use mod::test ; use Carp qw/cluck/; use Sub::UplevelFix ; # subroutine A calls subroutine B with uplevel(), so when # subroutine B queries caller(), it gets main as the caller (just # like subroutine A) instead of getting subroutine A sub sub_a { my $uplevel = 1; warn "\nEntering Subroutine A\n" ; cluck "Calling B with uplevel $uplevel" ; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; uplevel $uplevel, \&sub_b ; } sub sub_b { warn "\nEntering Subroutine B\n" ; cluck "Calling C" ; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; sub_c(); } sub sub_c { my $uplevel = 3; warn "\nEntering Subroutine C\n" ; cluck "Calling D with uplevel $uplevel" ; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; uplevel $uplevel, \&sub_d ; } sub sub_d { warn "\nEntering Subroutine D\n" ; cluck "Inside D"; warn "caller() says: ", join(", ", map { defined $_ ? $_ : 'undef' } (caller())[0 .. 2]), "\n" ; } sub_a() ;
Subject: Re: [rt.cpan.org #32335] Problem when stacking calls to uplevel
Date: Tue, 15 Jan 2008 21:54:34 -0500
To: bug-Sub-Uplevel [...] rt.cpan.org
From: "David Golden" <xdaveg [...] gmail.com>
Show quoted text
> This exactly reflects the call stack I think we should have. > main 4-> sub_a 3-> (uplevel(1) -> sub_b) 2-> sub_c 1-> (uplevel(3) -> sub_d) > If I call uplevel 3 i want my context to be 3 levels above my caller > which is main in sub_d. Don't you think ?
You have to remember that each call to uplevel subtracts an extra frame from the call stack -- i.e. uplevel always hides itself. So you call for 4 frames up from 2 separate uplevel calls -- or 6 levels up. That takes you to the top context, which is main in your diagram above as you say. But caller() from the top context returns undef -- i.e. the frame *above* the context. From sub_b, CORE::caller is the uplevel call. With the effects of the uplevel(1), caller() in sub_b returns the caller of the context one frame above the uplevel. And the caller of sub_a is main. So consider sub_d -- CORE::caller is the uplevel call. Consider the effects of different levels of upleveling on the value of caller() in sub_d: uplevel(1) -- return caller() of sub_c => sub_b uplevel(2) -- return caller() of sub_b => main (as per the example above) uplevel(3) -- return caller() of main => undef David
From: abc159abc [...] hotmail.com
On Tue Jan 15 21:54:57 2008, xdaveg@gmail.com wrote: Show quoted text
> > This exactly reflects the call stack I think we should have. > > main 4-> sub_a 3-> (uplevel(1) -> sub_b) 2-> sub_c 1-> (uplevel(3)
> -> sub_d)
> > If I call uplevel 3 i want my context to be 3 levels above my caller > > which is main in sub_d. Don't you think ?
> > You have to remember that each call to uplevel subtracts an extra > frame from the call stack -- i.e. uplevel always hides itself. So you > call for 4 frames up from 2 separate uplevel calls -- or 6 levels up. > That takes you to the top context, which is main in your diagram above > as you say. > > But caller() from the top context returns undef -- i.e. the frame > *above* the context. > > From sub_b, CORE::caller is the uplevel call. With the effects of the > uplevel(1), caller() in sub_b returns the caller of the context one > frame above the uplevel. And the caller of sub_a is main. > > So consider sub_d -- CORE::caller is the uplevel call. Consider the > effects of different levels of upleveling on the value of caller() in > sub_d: > > uplevel(1) -- return caller() of sub_c => sub_b > uplevel(2) -- return caller() of sub_b => main (as per the example > above) > uplevel(3) -- return caller() of main => undef > > David
I understand that uplevel hides itself, that's why I grouped it with the level where it is called in: main 4-> sub_a 3-> (uplevel(1) -> sub_b) 2-> sub_c 1-> (uplevel(3) -> sub_d) If I understood correctly, the point of uplevel if to fool the function we call by making it believe that its context is not the one just above but a certain number of frames above its normal context (that's what is written in the doc also). The original library returns fine until the call in sub_c. If you debug the lib you'll see that it is not only one level above main but sometimes more which I think is wrong. We want the caller function to believe it is n levels above the real caller so the real caller called in sub_d would return sub_c. Then overridden one will return as if we had called caller(n). in sub_d case if we remove all reference to uplevel caller(3) brings us in main. So if in sub_a you call uplevel 1 you want to go one level above sub_a which is main. Which means that calling caller() in sub_b will return main (the current level above sub_a). sub_b does not call uplevel so the caller() of sub_c is the normal one so it returns the level just above (sub_b). sub_c calls uplevel 3 so it wants sub_d to think that it is 3 levels above sub_c (1st level is sub_b, 2nd level is sub_a and 3rd level is main). That way it is consistent with the caller function which returns the contect n level above the immediate parent frame. Truly, If I had caller caller with any number other than zero I would surely have had undef. Does it makes sense ?
Subject: Re: [rt.cpan.org #32335] Problem when stacking calls to uplevel
Date: Wed, 16 Jan 2008 20:30:22 -0500
To: bug-Sub-Uplevel [...] rt.cpan.org
From: "David Golden" <dagolden [...] cpan.org>
On Jan 16, 2008 9:04 AM, vive via RT <bug-Sub-Uplevel@rt.cpan.org> wrote: Show quoted text
> The original library returns fine until the call in sub_c. If you debug > the lib you'll see that it is not only one level above main but > sometimes more which I think is wrong.
Can you give me an example? Show quoted text
> So if in sub_a you call uplevel 1 you want to go one level above sub_a > which is main. Which means that calling caller() in sub_b will return > main (the current level above sub_a). > sub_b does not call uplevel so the caller() of sub_c is the normal one > so it returns the level just above (sub_b). > sub_c calls uplevel 3 so it wants sub_d to think that it is 3 levels > above sub_c (1st level is sub_b, 2nd level is sub_a and 3rd level is main).
What I think you are neglecting is that you've already called uplevel to invoke sub_b, so the level above sub_b is main, not sub_a. (As you say above, caller() in sub_b will return main) Until the uplevel invocation of sub_b completes, sub_a is hidden from attempts to examine the call stack. So in your terms, the 2nd level is main and the 3rd level is undef. In your other example, without any uplevel calls, caller(3) in sub_d returns main -- that's because the call stack looks like this: (4) main -- caller(0) gives undef (3) sub_a -- caller(0) gives main (2) sub_b -- caller(0) gives sub_a (1) sub_c -- caller(0) gives sub_b (0) sub_d -- caller(0) gives sub_c So caller(3) gives the same result as caller(0) in sub_a which is main. If you called uplevel 3 in sub_c to invoke sub_d, but didn't call uplevel in sub_a, you'd get this, which sub_d appearing to be 3 frames higher than the uplevel call: (1) main -- caller(0) gives undef (0) sub_d -- caller(0) gives main But now if you start with uplevel 1 in sub_a to invoke sub_b, you first get this: (1) main -- caller(0) gives undef (0) sub_b -- caller(0) gives main Then, if you proceeded to sub_d *without* uplevel you would get this: (3) main -- caller(0) gives undef (2) sub_b -- caller(0) gives main (1) sub_c -- caller(0) gives sub_b (0) sub_d -- caller(0) gives sub_c Then, if you add uplevel 3, sub_d appears to be three frames higher, or just this: (0) sub_d -- caller(0) gives undef Does that help clarify? David
From: abc159abc [...] hotmail.com
On Wed Jan 16 20:30:40 2008, DAGOLDEN wrote: Show quoted text
> On Jan 16, 2008 9:04 AM, vive via RT <bug-Sub-Uplevel@rt.cpan.org> > wrote:
> > The original library returns fine until the call in sub_c. If you
> debug
> > the lib you'll see that it is not only one level above main but > > sometimes more which I think is wrong.
> > Can you give me an example? >
> > So if in sub_a you call uplevel 1 you want to go one level above
> sub_a
> > which is main. Which means that calling caller() in sub_b will
> return
> > main (the current level above sub_a). > > sub_b does not call uplevel so the caller() of sub_c is the normal
> one
> > so it returns the level just above (sub_b). > > sub_c calls uplevel 3 so it wants sub_d to think that it is 3 levels > > above sub_c (1st level is sub_b, 2nd level is sub_a and 3rd level is
> main). > > What I think you are neglecting is that you've already called uplevel > to invoke sub_b, so the level above sub_b is main, not sub_a. (As you > say above, caller() in sub_b will return main) Until the uplevel > invocation of sub_b completes, sub_a is hidden from attempts to > examine the call stack. So in your terms, the 2nd level is main and > the 3rd level is undef. > > In your other example, without any uplevel calls, caller(3) in sub_d > returns main -- that's because the call stack looks like this: > > (4) main -- caller(0) gives undef > (3) sub_a -- caller(0) gives main > (2) sub_b -- caller(0) gives sub_a > (1) sub_c -- caller(0) gives sub_b > (0) sub_d -- caller(0) gives sub_c > > So caller(3) gives the same result as caller(0) in sub_a which is > main. > > If you called uplevel 3 in sub_c to invoke sub_d, but didn't call > uplevel in sub_a, you'd get this, which sub_d appearing to be 3 frames > higher than the uplevel call: > > (1) main -- caller(0) gives undef > (0) sub_d -- caller(0) gives main > > But now if you start with uplevel 1 in sub_a to invoke sub_b, you > first get this: > > (1) main -- caller(0) gives undef > (0) sub_b -- caller(0) gives main > > Then, if you proceeded to sub_d *without* uplevel you would get this: > > (3) main -- caller(0) gives undef > (2) sub_b -- caller(0) gives main > (1) sub_c -- caller(0) gives sub_b > (0) sub_d -- caller(0) gives sub_c > > Then, if you add uplevel 3, sub_d appears to be three frames higher, > or just this: > > (0) sub_d -- caller(0) gives undef > > Does that help clarify? > > David
OMG, I just saw I am completely stupid. Actually I was more focused on what I wanted to get than what you wanted to give in your package :) I wanted to change the context relatively to the original call stack where you propose to change the context in the call stack after the modifications operated by the previous call to uplevel. Sorry to have wasted your time ... Maybe one comment. I know that if you call caller (the original one) with a stack frame number higher than the highest one it returns undef. However in uplevel we want to change the context of a function call and I don't think it is valid, event if it is fake, to say that the context is undef (caller in sub_d). So I suggest either you force the level to main if it is to big or you just don't execute the function in that case.
Subject: Re: [rt.cpan.org #32335] Problem when stacking calls to uplevel
Date: Thu, 17 Jan 2008 13:32:02 -0500
To: bug-Sub-Uplevel [...] rt.cpan.org
From: "David Golden" <dagolden [...] cpan.org>
On Jan 17, 2008 12:06 PM, vive via RT <bug-Sub-Uplevel@rt.cpan.org> wrote: Show quoted text
> I wanted to change the context relatively to the original call stack > where you propose to change the context in the call stack after the > modifications operated by the previous call to uplevel. > > Sorry to have wasted your time ...
Not at all! Uplevel is a really weird, hacky thing. It's helpful to me to work through the edge cases from time to time and make sure it's doing what I think it should be doing. Show quoted text
> Maybe one comment. I know that if you call caller (the original one) > with a stack frame number higher than the highest one it returns undef. > However in uplevel we want to change the context of a function call and > I don't think it is valid, event if it is fake, to say that the context > is undef (caller in sub_d). So I suggest either you force the level to > main if it is to big or you just don't execute the function in that case.
There's no reason someone couldn't uplevel a function from main -- to make a function look like it's running at the top level. So I'm reluctant to make the behavior change at some levels and not others. However, I am inclined to issue a warning if the uplevel would take someone *beyond* main -- the stack should never look negative. Empty is OK, but not negative. David
From: abc159abc [...] hotmail.com
On Thu Jan 17 13:32:32 2008, DAGOLDEN wrote: Show quoted text
> On Jan 17, 2008 12:06 PM, vive via RT <bug-Sub-Uplevel@rt.cpan.org> wrote:
> > I wanted to change the context relatively to the original call stack > > where you propose to change the context in the call stack after the > > modifications operated by the previous call to uplevel. > > > > Sorry to have wasted your time ...
> > Not at all! Uplevel is a really weird, hacky thing. It's helpful to > me to work through the edge cases from time to time and make sure it's > doing what I think it should be doing. >
> > Maybe one comment. I know that if you call caller (the original one) > > with a stack frame number higher than the highest one it returns undef. > > However in uplevel we want to change the context of a function call and > > I don't think it is valid, event if it is fake, to say that the context > > is undef (caller in sub_d). So I suggest either you force the level to > > main if it is to big or you just don't execute the function in that
case. Show quoted text
> > There's no reason someone couldn't uplevel a function from main -- to > make a function look like it's running at the top level. So I'm > reluctant to make the behavior change at some levels and not others. > > However, I am inclined to issue a warning if the uplevel would take > someone *beyond* main -- the stack should never look negative. Empty > is OK, but not negative. > > David
Ok, it's fine for me. The warning is really as you wish. I'll just keep my little modification locally and test for undef and it should be ok. Thank you!
Patched repository to include a warning if uplevel call is for more than the stack depth. Will be in the next release. David