Skip to content

Commit 5c0551a

Browse files
committed
(perl #126760) adapt sigtrap for layers on STDERR.
sigtrap defines a signal handler apparently intended to be called under unsafe signals, since a) the code was written before safe signals were implemented and b) it uses syswrite() for output and avoid creating new SVs where it can. Unfortunately syswrite() doesn't handle PerlIO layers, *and* with syswrite() being disallowed for :utf8 handlers, throws an exception. This causes the sigtrap tests to fail if PERL_UNICODE is set and the current locale is a UTF-8 locale. I want to avoid allocating new SVs until the point where the code originally did so, so the code now attempts a syswrite() under eval, falling back to print, and then at the point where the original code started allocating SVs uses PerlIO::get_layers() to check if any layers might make a difference to the output.
1 parent 1ed4b77 commit 5c0551a

File tree

1 file changed

+47
-9
lines changed

1 file changed

+47
-9
lines changed

lib/sigtrap.pm

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ sigtrap - Perl pragma to enable simple signal handling
88

99
use Carp;
1010

11-
$VERSION = 1.08;
11+
$VERSION = 1.09;
1212
$Verbose ||= 0;
1313

1414
sub import {
@@ -81,16 +81,49 @@ sub handler_die {
8181

8282
sub handler_traceback {
8383
package DB; # To get subroutine args.
84+
my $use_print;
8485
$SIG{'ABRT'} = DEFAULT;
8586
kill 'ABRT', $$ if $panic++;
86-
syswrite(STDERR, 'Caught a SIG', 12);
87-
syswrite(STDERR, $_[0], length($_[0]));
88-
syswrite(STDERR, ' at ', 4);
87+
88+
# This function might be called as an unsafe signal handler, so it
89+
# tries to delay any memory allocations as long as possible.
90+
#
91+
# Unfortunately with PerlIO layers, using syswrite() here has always
92+
# been broken.
93+
#
94+
# Calling PerlIO::get_layers() here is tempting, but that does
95+
# allocations, which we're trying to avoid for this early code.
96+
if (eval { syswrite(STDERR, 'Caught a SIG', 12); 1 }) {
97+
syswrite(STDERR, $_[0], length($_[0]));
98+
syswrite(STDERR, ' at ', 4);
99+
}
100+
else {
101+
print STDERR 'Caught a SIG', $_[0], ' at ';
102+
++$use_print;
103+
}
104+
89105
($pack,$file,$line) = caller;
90-
syswrite(STDERR, $file, length($file));
91-
syswrite(STDERR, ' line ', 6);
92-
syswrite(STDERR, $line, length($line));
93-
syswrite(STDERR, "\n", 1);
106+
unless ($use_print) {
107+
syswrite(STDERR, $file, length($file));
108+
syswrite(STDERR, ' line ', 6);
109+
syswrite(STDERR, $line, length($line));
110+
syswrite(STDERR, "\n", 1);
111+
}
112+
else {
113+
print STDERR $file, ' line ', $line, "\n";
114+
}
115+
116+
# we've got our basic output done, from now on we can be freer with allocations
117+
# find out whether we have any layers we need to worry about
118+
unless ($use_print) {
119+
my @layers = PerlIO::get_layers(*STDERR);
120+
for my $name (@layers) {
121+
unless ($name =~ /^(unix|perlio)$/) {
122+
++$use_print;
123+
last;
124+
}
125+
}
126+
}
94127

95128
# Now go for broke.
96129
for ($i = 1; ($p,$f,$l,$s,$h,$w,$e,$r) = caller($i); $i++) {
@@ -116,7 +149,12 @@ sub handler_traceback {
116149
}
117150
$f = "file '$f'" unless $f eq '-e';
118151
$mess = "$w$s$a called from $f line $l\n";
119-
syswrite(STDERR, $mess, length($mess));
152+
if ($use_print) {
153+
print STDERR $mess;
154+
}
155+
else {
156+
syswrite(STDERR, $mess, length($mess));
157+
}
120158
}
121159
kill 'ABRT', $$;
122160
}

0 commit comments

Comments
 (0)