develooper Front page | perl.perl5.porters | Postings from September 2003

Re: [perl #23810] Tied methods break when combined with eval() of failing compile-time code

Thread Previous
From:
Dave Mitchell
Date:
September 26, 2003 15:06
Subject:
Re: [perl #23810] Tied methods break when combined with eval() of failing compile-time code
Message ID:
20030926220559.GA3933@fdgroup.com
On Mon, Sep 15, 2003 at 09:18:13AM -0000, Jason Rhinelander wrote:
> The following example demonstrates the problem quite well:
> 
> perl -e '
> package Breaks;
> use Tie::Hash;
> @ISA = qw(Tie::StdHash);
> sub FETCH { eval "BEGIN { some bad code }"; return 1 }
> 
> package main;
> my %foo;
> my $f = tie %foo, "Breaks";
> 
> print "Calling FETCH explicitly ...\n";
> $f->FETCH("bar");
> 
> print "\tdone.\nCalling FETCH implicitly ...\n";
> $foo{bar};
> 
> print "\tdone.\n"
> '
> 
> The output from this is:
> 
> Calling FETCH explicitly ...
>         done.
> Calling FETCH implicitly ...
> Can't return outside a subroutine at -e line 5.

Perl is incorrectly popping too much context off the stack in the implicit
case.

Executing similar code (where I replaced the BEGIN {..} with BEGIN {die },
I found the following stack state immediately before and after pp_die() is
executed:

------------
implicit call
-------------

STACK 0: MAIN
  CX 0: BLOCK  => HV()  PVIV("bar")  
  retop=(null)
STACK 1: MAGIC
  CX 0: SUB    => 
  retop=nextstate
  CX 1: EVAL   => *  CV(BEGIN)  
  retop=(null)
  CX 2: EVAL   => 
  retop=(null)
  CX 3: SUB    => *  

((eval 2):1)	die

STACK 0: MAIN
  CX 0: BLOCK  => HV()  PVIV("bar")  
  retop=(null)


------------
explicit call
-------------


STACK 0: MAIN
  CX 0: BLOCK  => 
  retop=nextstate
  CX 1: SUB    => 
  retop=nextstate
  CX 2: EVAL   => *  CV(BEGIN)  
  retop=(null)
  CX 3: EVAL   => 
  retop=(null)
  CX 4: SUB    => *  

((eval 1):1)	die

STACK 0: MAIN
  CX 0: BLOCK  => 
  retop=nextstate
  CX 1: SUB    => 


(Note that in the implicit case, there are two context stacks, due to
the tied call).
The explicit case correctly pops off the eval stuff, leaving you in the
context that's executing the FETCH sub. The implicit case manages to lose
the sub context too.

tracing the code shows that die_where correctly pops the EVAL/EVAL/SUB,
then vdie() does a JMPENV_JUMP(3), which pops the C stack back to the
outermost execution spot in perl_run(), which then does
POPSTACK_TO(PL_mainstack), which I guess screws things up when threre's
more than one context stack.

At this point I give up, since the mechanisms for longjmping in Perl for
exception handling is way beyond this particular Bear of Little Brain. In
this matter, longjmping can be considered similar to the
Schleswig-Holstein question, which - in the words of Lord Palmerston - "only
three persons understood [...]: one is dead, one went mad and I have
forgotten". Now which one of those three applies to Sarathy, I wonder? ;-)

Dave.

-- 
My get-up-and-go just got up and went.

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About