summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2015-10-30 20:40:40 +0000
committerSteve Hay <steve.m.hay@googlemail.com>2015-10-30 20:41:14 +0000
commit15926ed4fbda102f61617e5dffe81ca7264cfafd (patch)
treeca25e9d5c9c82a324916122ede314fb8d0541d24
parentda2374c67f748345727694af6c33df22e3cfc40a (diff)
downloadperl-15926ed4fbda102f61617e5dffe81ca7264cfafd.tar.gz
[perl #126229] POSIX::strerror() clears $!
If POSIX::strerror is passed $! as its arg, then it ends up doing local $! = $!, which due to a bug in the localisation system, leaves $! undef even after scope exit. Work around the bug by assigning $_[0] to a my var first. (cherry picked from commit 068e3fb46a24909060201961a41f2ab7fb778caf) [POSIX.pm not $VERSION bumped, since it was already bumped by commit ad5de5ac637094e4afcf8b206056a9202288aa76]
-rw-r--r--ext/POSIX/lib/POSIX.pm2
-rw-r--r--ext/POSIX/t/strerror_errno.t7
2 files changed, 8 insertions, 1 deletions
diff --git a/ext/POSIX/lib/POSIX.pm b/ext/POSIX/lib/POSIX.pm
index af416b55ae..6fc0e7518e 100644
--- a/ext/POSIX/lib/POSIX.pm
+++ b/ext/POSIX/lib/POSIX.pm
@@ -151,7 +151,7 @@ my %reimpl = (
exit => 'status => CORE::exit($_[0])',
getenv => 'name => $ENV{$_[0]}',
system => 'command => CORE::system($_[0])',
- strerror => 'errno => BEGIN { local $!; require locale; locale->import} local $! = $_[0]; "$!"',
+ strerror => 'errno => BEGIN { local $!; require locale; locale->import} my $e = $_[0] + 0; local $!; $! = $e; "$!"',
strstr => 'big, little => CORE::index($_[0], $_[1])',
chmod => 'mode, filename => CORE::chmod($_[0], $_[1])',
fstat => 'fd => CORE::open my $dup, "<&", $_[0]; CORE::stat($dup)', # Gross.
diff --git a/ext/POSIX/t/strerror_errno.t b/ext/POSIX/t/strerror_errno.t
index 4807a8d910..df691f177f 100644
--- a/ext/POSIX/t/strerror_errno.t
+++ b/ext/POSIX/t/strerror_errno.t
@@ -14,4 +14,11 @@ $! = 1;
POSIX::strerror(1);
is (0+$!, 1, 'strerror doesn\'t destroy $!');
+# [perl #126229] POSIX::strerror() clears $!
+{
+ local $! = 29;
+ my $e = POSIX::strerror($!);
+ is (0+$!, 29);
+}
+
done_testing();