-
Notifications
You must be signed in to change notification settings - Fork 561
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fully implement documented $SIG{__WARN/DIE__} behavior
The documentation for %SIG (in perlvar) states: > The `__DIE__` handler is explicitly disabled during the call, so that > you can die from a `__DIE__` handler. Similarly for `__WARN__`. This has never really been true. There were two basic checks to prevent infinite recursion from a __DIE__ or __WARN__ handler: 1. When an exception is thrown, if $SIG{__DIE__} references a subroutine that is currently active (somewhere on the call stack at the point of the exception), then die() unwinds the stack directly, bypassing the handler. (The same applies mutatis mutandis to $SIG{__WARN__}/warn().) This behavior is wrong because the subroutine may have been invoked normally first (i.e. not via the %SIG machinery), so the handler should still kick in. This is bug GH #22984. It also causes issues if the subroutine transfers control "sideways" via goto &othersub because then the registered handler is no longer considered "active" even though Perl code is still executing in the context of a __DIE__/__WARN__ handler. Then, if the goto'd &othersub triggers a warning/exception, the __DIE__/__WARN__ handler will be invoked recursively, eventually leading to a C stack overflow. This is bug GH #14527. 2. The code for $SIG{__WARN__} (since c5be5b4) and $SIG{__DIE__} (since 8b4094f) mitigates the latter issue by internally unsetting the __DIE__/__WARN__ hooks for the duration of the handler call. Unfortunately, this is not a complete fix because any modification of $SIG{__DIE__}/$SIG{__WARN__} within the handler, even seeming no-ops such as $SIG{__DIE__} = $SIG{__DIE__} or { local $SIG{__DIE__}; }, will reïnstate the internal hooks, thus reärming the __DIE__/__WARN__ handlers. This is bug GH #22987. This patch adds two interpreter-global variables that record whether we are currently executing a __DIE__/__WARN__ handler. This fully replaces the old heuristics by a precise check that prevents recursive handler invocation and nothing more. Exporter::Heavy had to be patched because it relied on the old (buggy) behavior: It registered a $SIG{__WARN__} handler that would reässign $SIG{__WARN__} and then call warn(), expecting the new handler to be called (i.e. two (nested) warn hooks to be active simultaneously). This is no longer possible with the new implementation. Fixes #22984, #22987.
- Loading branch information
Showing
9 changed files
with
81 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,64 @@ | ||
#!./perl -w | ||
#!./perl | ||
use v5.36; | ||
|
||
# This test checks for RT #123878/GH #14527, keeping the die handler still | ||
# disabled into goto'd function. And the other documented | ||
# exceptions to enable dying from a die handler. | ||
|
||
print "1..4\n"; | ||
print "1..6\n"; | ||
|
||
eval { | ||
sub f1 { die "ok 1\n" } | ||
$SIG{__DIE__} = \&f1; | ||
die; | ||
sub f1 { die "ok 1\n" } | ||
$SIG{__DIE__} = \&f1; | ||
die; | ||
}; | ||
print $@; | ||
|
||
eval { | ||
sub loopexit { for (0..2) { next if $_ } } | ||
$SIG{__DIE__} = \&loopexit; | ||
die "ok 2\n"; | ||
sub loopexit { for (0..2) { next if $_ } } | ||
$SIG{__DIE__} = \&loopexit; | ||
die "ok 2\n"; | ||
}; | ||
print $@; | ||
|
||
eval { | ||
sub foo1 { die "ok 3\n" } | ||
sub bar1 { foo1() } | ||
$SIG{__DIE__} = \&bar1; | ||
die; | ||
sub foo1 { die "ok 3\n" } | ||
sub bar1 { foo1() } | ||
$SIG{__DIE__} = \&bar1; | ||
die; | ||
}; | ||
print $@; | ||
|
||
# GH #14527 | ||
eval { | ||
sub foo2 { die "ok 4\n" } | ||
sub bar2 { goto &foo2 } | ||
$SIG{__DIE__} = \&bar2; | ||
die; | ||
sub foo2 { die "ok 4\n" } | ||
sub bar2 { goto &foo2 } | ||
$SIG{__DIE__} = \&bar2; | ||
die; | ||
}; | ||
print $@; | ||
# Deep recursion on subroutine "main::foo2" at t/op/die_goto.t line 35. | ||
# Segmentation fault (core dumped) | ||
|
||
# Deep recursion on subroutine "main::foo2" at t/op/die_goto.t line 32. | ||
# GH #22987 (die) | ||
eval { | ||
sub foo3 { die "ok 5\n" } | ||
sub bar3 { { local $SIG{__DIE__}; } goto &foo3 } | ||
$SIG{__DIE__} = \&bar3; | ||
die; | ||
}; | ||
print $@; | ||
# Deep recursion on subroutine "main::foo3" at t/op/die_goto.t line 46. | ||
# Segmentation fault (core dumped) | ||
|
||
# GH #22984 | ||
eval { | ||
my $called = 0; | ||
sub hybrid { | ||
$called++; | ||
die "$called\n"; | ||
} | ||
$SIG{__DIE__} = \&hybrid; | ||
hybrid; | ||
}; | ||
print $@ eq "2\n" ? "ok 6\n" : "not ok 6\n" . "\$\@ = $@" =~ s/^/# /mgr; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters