In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/22a30693fc87702395761f2f556d3f49e6c89c3d?hp=095a5c3e83eb5f5932cdf8d475a61091dbf274e3>
- Log ----------------------------------------------------------------- commit 22a30693fc87702395761f2f556d3f49e6c89c3d Author: Zefram <zef...@fysh.org> Date: Mon Dec 6 22:21:19 2010 +0000 stopgap hack for $@ as unwinding reason indicator Set $@ early in a die as well as late, so that it continues to function as an unreliable indicator of whether unwinding in progress is due to an exception. This is a stopgap arrangement, until the unwinding process can be introspected properly. ----------------------------------------------------------------------- Summary of changes: MANIFEST | 1 + pp_ctl.c | 34 ++++++++++++++++++++++++ t/op/die_unwind.t | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 0 deletions(-) create mode 100644 t/op/die_unwind.t diff --git a/MANIFEST b/MANIFEST index 1a9de2d..ad0660d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -4652,6 +4652,7 @@ t/op/die_except.t See if die/eval avoids $@ clobberage t/op/die_exit.t See if die and exit status interaction works t/op/die_keeperr.t See if G_KEEPERR works for destructors t/op/die.t See if die works +t/op/die_unwind.t Check die/eval early-$@ backcompat hack t/op/dor.t See if defined-or (//) works t/op/do.t See if subroutines work t/op/each_array.t See if array iterators work diff --git a/pp_ctl.c b/pp_ctl.c index fa25681..48a4e41 100644 --- a/pp_ctl.c +++ b/pp_ctl.c @@ -1645,6 +1645,40 @@ Perl_die_unwind(pTHX_ SV *msv) I32 cxix; I32 gimme; + /* + * Historically, perl used to set ERRSV ($@) early in the die + * process and rely on it not getting clobbered during unwinding. + * That sucked, because it was liable to get clobbered, so the + * setting of ERRSV used to emit the exception from eval{} has + * been moved to much later, after unwinding (see just before + * JMPENV_JUMP below). However, some modules were relying on the + * early setting, by examining $@ during unwinding to use it as + * a flag indicating whether the current unwinding was caused by + * an exception. It was never a reliable flag for that purpose, + * being totally open to false positives even without actual + * clobberage, but was useful enough for production code to + * semantically rely on it. + * + * We'd like to have a proper introspective interface that + * explicitly describes the reason for whatever unwinding + * operations are currently in progress, so that those modules + * work reliably and $@ isn't further overloaded. But we don't + * have one yet. In its absence, as a stopgap measure, ERRSV is + * now *additionally* set here, before unwinding, to serve as the + * (unreliable) flag that it used to. + * + * This behaviour is temporary, and should be removed when a + * proper way to detect exceptional unwinding has been developed. + * As of 2010-12, the authors of modules relying on the hack + * are aware of the issue, because the modules failed on + * perls 5.13.{1..7} which had late setting of $@ without this + * early-setting hack. + */ + if (!(in_eval & EVAL_KEEPERR)) { + SvTEMP_off(exceptsv); + sv_setsv(ERRSV, exceptsv); + } + while ((cxix = dopoptoeval(cxstack_ix)) < 0 && PL_curstackinfo->si_prev) { diff --git a/t/op/die_unwind.t b/t/op/die_unwind.t new file mode 100644 index 0000000..36772c4 --- /dev/null +++ b/t/op/die_unwind.t @@ -0,0 +1,74 @@ +#!./perl + +# +# This test checks for $@ being set early during an exceptional +# unwinding, and that this early setting doesn't affect the late +# setting used to emit the exception from eval{}. The early setting is +# a backward-compatibility hack to satisfy modules that were relying on +# the historical early setting in order to detect exceptional unwinding. +# This hack should be removed when a proper way to detect exceptional +# unwinding has been developed. +# + +print "1..12\n"; +my $test_num = 0; +sub ok { + print $_[0] ? "" : "not ", "ok ", ++$test_num, "\n"; +} + +{ + package End; + sub DESTROY { $_[0]->() } + sub main::end(&) { + my($cleanup) = @_; + return bless(sub { $cleanup->() }, "End"); + } +} + +my($uerr, $val, $err); + +$@ = ""; +$val = eval { + my $c = end { $uerr = $@; $@ = "t2\n"; }; + 1; +}; $err = $@; +ok $uerr eq ""; +ok $val == 1; +ok $err eq ""; + +$@ = "t0\n"; +$val = eval { + $@ = "t1\n"; + my $c = end { $uerr = $@; $@ = "t2\n"; }; + 1; +}; $err = $@; +ok $uerr eq "t1\n"; +ok $val == 1; +ok $err eq ""; + +$@ = ""; +$val = eval { + my $c = end { $uerr = $@; $@ = "t2\n"; }; + do { + die "t3\n"; + }; + 1; +}; $err = $@; +ok $uerr eq "t3\n"; +ok !defined($val); +ok $err eq "t3\n"; + +$@ = "t0\n"; +$val = eval { + $@ = "t1\n"; + my $c = end { $uerr = $@; $@ = "t2\n"; }; + do { + die "t3\n"; + }; + 1; +}; $err = $@; +ok $uerr eq "t3\n"; +ok !defined($val); +ok $err eq "t3\n"; + +1; -- Perl5 Master Repository