Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Carp: Avoid run-time mods; StrVal workarounds
Carp needs to avoid loading modules while reporting errors, because it may be invoked via $SIG{__DIE__} after a syntax error, when BEGIN blocks are forbidden. Before this commit (as of v5.27.8-360-gc99363a) it was doing just that for reference arguments within stack traces. That means we either need to load overload.pm at start-up so that overload::StrVal is already available, or avoid overload::StrVal altogether. It turns out that various versions of overload::StrVal have their own problems that prevent Carp from using them (out- lined in the comments added to Carp.pm and also described at <https://rt.perl.org/Ticket/Display.html?id=132902#txn-1535564>). So we now follow two approaches: If overloading.pm is available, use that; otherwise, use a hideous workaround inspired by ancient imple- entations of overload::StrVal and Scalar::Util::blessed, while avoid- ing the bugs in those old versions.
- Loading branch information
Father Chrysostomos
committed
Feb 27, 2018
1 parent
f88ca57
commit 5c8d107
Showing
4 changed files
with
148 additions
and
29 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
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 |
---|---|---|
@@ -0,0 +1,73 @@ | ||
use Config; | ||
use IPC::Open3 1.0103 qw(open3); | ||
use Test::More tests => 4; | ||
|
||
sub runperl { | ||
my(%args) = @_; | ||
my($w, $r); | ||
|
||
local $ENV{PERL5LIB} = join ($Config::Config{path_sep}, @INC); | ||
|
||
my $pid = open3($w, $r, undef, $^X, "-e", $args{prog}); | ||
close $w; | ||
my $output = ""; | ||
while(<$r>) { $output .= $_; } | ||
waitpid($pid, 0); | ||
return $output; | ||
} | ||
|
||
|
||
# Make sure we don’t try to load modules on demand in the presence of over- | ||
# loaded args. If there has been a syntax error, they won’t load. | ||
like( | ||
runperl( | ||
prog => q< | ||
use Carp; | ||
sub foom { | ||
Carp::confess("Looks lark we got a error: $_[0]") | ||
} | ||
BEGIN { | ||
*{"o::()"} = sub {}; | ||
*{'o::(""'} = sub {"hay"}; | ||
$o::OVERLOAD{dummy}++; # perls before 5.18 need this | ||
*{"CODE::()"} = sub {}; | ||
$SIG{__DIE__} = sub { foom (@_, bless([], o), sub {}) } | ||
} | ||
$a + | ||
>, | ||
), | ||
qr 'Looks lark.*o=ARRAY.* CODE's, | ||
'Carp does not try to load modules on demand for overloaded args', | ||
); | ||
|
||
# Run the test also in the presence of | ||
# a) A UNIVERSAL::can module | ||
# b) A UNIVERSAL::isa module | ||
# c) Both | ||
# since they follow slightly different code paths on old pre-5.10.1 perls. | ||
my $prog = q< | ||
use Carp; | ||
sub foom { | ||
Carp::confess("Looks lark we got a error: $_[0]") | ||
} | ||
BEGIN { | ||
*{"o::()"} = sub {}; | ||
*{'o::(""'} = sub {"hay"}; | ||
$o::OVERLOAD{dummy}++; # perls before 5.18 need this | ||
*{"CODE::()"} = sub {}; | ||
$SIG{__DIE__} = sub { foom (@_, bless([], o), sub{}) } | ||
} | ||
$a + | ||
>; | ||
for ( | ||
["UNIVERSAL::isa", 'BEGIN { $UNIVERSAL::isa::VERSION = 1 }'], | ||
["UNIVERSAL::can", 'BEGIN { $UNIVERSAL::can::VERSION = 1 }'], | ||
["UNIVERSAL::can/isa", 'BEGIN { $UNIVERSAL::can::VERSION = | ||
$UNIVERSAL::isa::VERSION = 1 }'], | ||
) { | ||
my ($tn, $preamble) = @$_; | ||
like(runperl( prog => "$preamble$prog" ), | ||
qr 'Looks lark.*o=ARRAY.* CODE's, | ||
"StrVal fallback in the presence of $tn", | ||
) | ||
} |
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,27 +1,25 @@ | ||
BEGIN { print "1..6\n"; } | ||
BEGIN { print "1..5\n"; } | ||
|
||
our $has_utf8; BEGIN { $has_utf8 = exists($::{"utf8::"}); } | ||
our $has_overload; BEGIN { $has_overload = exists($::{"overload::"}); } | ||
our $has_B; BEGIN { $has_B = exists($::{"B::"}); } | ||
our $has_UNIVERSAL_isa; BEGIN { $has_UNIVERSAL_isa = exists($UNIVERSAL::{"isa::"}); } | ||
|
||
use Carp; | ||
sub { sub { Carp::longmess("x") }->() }->(\1, "\x{2603}", qr/\x{2603}/); | ||
|
||
print !(exists($::{"utf8::"}) xor $has_utf8) ? "" : "not ", "ok 1 # used utf8\n"; | ||
print !(exists($::{"overload::"}) xor $has_overload) ? "" : "not ", "ok 2 # used overload\n"; | ||
print !(exists($::{"B::"}) xor $has_B) ? "" : "not ", "ok 3 # used B\n"; | ||
print !(exists($UNIVERSAL::{"isa::"}) xor $has_UNIVERSAL_isa) ? "" : "not ", "ok 4 # used UNIVERSAL::isa\n"; | ||
print !(exists($::{"B::"}) xor $has_B) ? "" : "not ", "ok 2 # used B\n"; | ||
print !(exists($UNIVERSAL::{"isa::"}) xor $has_UNIVERSAL_isa) ? "" : "not ", "ok 3 # used UNIVERSAL::isa\n"; | ||
|
||
# Autovivify $::{"overload::"} | ||
() = \$::{"overload::"}; | ||
() = \$::{"utf8::"}; | ||
eval { sub { Carp::longmess() }->(\1) }; | ||
print $@ eq '' ? "ok 5 # longmess check1\n" : "not ok 5 # longmess check1\n# $@"; | ||
print $@ eq '' ? "ok 4 # longmess check1\n" : "not ok 4 # longmess check1\n# $@"; | ||
|
||
# overload:: glob without hash | ||
undef *{"overload::"}; | ||
eval { sub { Carp::longmess() }->(\1) }; | ||
print $@ eq '' ? "ok 6 # longmess check2\n" : "not ok 6 # longmess check2\n# $@"; | ||
print $@ eq '' ? "ok 5 # longmess check2\n" : "not ok 5 # longmess check2\n# $@"; | ||
|
||
1; |