develooper Front page | perl.perl5.porters | Postings from June 2016

Re: Confused by eval behavior

Thread Previous | Thread Next
From:
Dave Mitchell
Date:
June 30, 2016 11:46
Subject:
Re: Confused by eval behavior
Message ID:
20160630113725.GH17054@iabyn.com
On Mon, Jun 27, 2016 at 02:36:38PM -0400, John Siracusa wrote:
> This new example looks even more like a bug:

I've just pushed this branch for smoking:

    smoke-me/davem/eval_temps

It does some general refactoring and tweaking of the eval popping code
blocks, then does this commit:

    FREEMPS when leaving eval, even when void or dying
    
    When a scope is exited normally (e.g. pp_leavetry, pp_leavesub),
    we do a FREETMPS only in scalar or list context; in void context
    we don't bother for efficiency reasons. Similarly, when there's an
    exception and we unwind to (and then pop) an EVAL context, we haven't
    been bothering to FREETMPS.
    
    The problem with this in try/eval (exiting normally or via an exception)
    is that it can delay some SVs getting freed until *after* $@ has been
    set. If that freeing calls a destructor which happens to set $@,
    then that overwrites the "real" value of $@.
    
    For example
    
        sub DESTROY { eval { die "died in DESTROY"; } }
        eval { bless []; };
        is ($@, "");
    
    Before this commit, that test would fail because $@ is "died in DESTROY".
    
    This commit ensures that leaving an eval/try by whatever means always
    clears the tmps stack before setting $@.
    
    See http://nntp.perl.org/group/perl.perl5.porters/237380.
    
    For now, I haven't added a FREETMPS to the other pp_leavefoo()
    void context cases, since I can't think of a case where it would
    matter.


It includes the following tests, which all failed on blead, and now all
pass:

    {
        package TMPS;
        sub DESTROY { eval { die "died in DESTROY"; } } # alters $@

        eval { { 1; { 1; bless []; } } };
        ::is ($@, "", "FREETMPS: normal try exit");

        eval q{ { 1; { 1; bless []; } } };
        ::is ($@, "", "FREETMPS: normal string eval exit");

        eval { { 1; { 1; return bless []; } } };
        ::is ($@, "", "FREETMPS: return try exit");

        eval q{ { 1; { 1; return bless []; } } };
        ::is ($@, "", "FREETMPS: return string eval exit");

        eval { { 1; { 1; my $x = bless []; die $x = 0, "die in eval"; } } };
        ::like ($@, qr/die in eval/, "FREETMPS: die try exit");

        eval q{ { 1; { 1; my $x = bless []; die $x = 0, "die in eval"; } } };
        ::like ($@, qr/die in eval/, "FREETMPS: die eval string exit");
    }


-- 
Wesley Crusher gets beaten up by his classmates for being a smarmy git,
and consequently has a go at making some friends of his own age for a
change.
    -- Things That Never Happen in "Star Trek" #18

Thread Previous | Thread Next


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