From c32fa775fbe3ba6a2e9daa54372f698e6c46683b Mon Sep 17 00:00:00 2001 From: Lukas Mai Date: Wed, 30 Jul 2025 00:31:09 +0200 Subject: [PATCH] File::stat: don't die on references Only treat arguments as bareword filehandles if they're plain strings, not references. Otherwise Symbol::qualify() will just return $arg as-is, even if it is not a GLOB reference. Fixes #23507. --- lib/File/stat.pm | 18 ++++++++++-------- lib/File/stat.t | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/lib/File/stat.pm b/lib/File/stat.pm index a2a2b09b56b7..192df7bbdb42 100644 --- a/lib/File/stat.pm +++ b/lib/File/stat.pm @@ -1,4 +1,4 @@ -package File::stat 1.14; +package File::stat 1.15; use v5.38; use warnings::register; @@ -200,14 +200,16 @@ sub stat :prototype($) { my $arg = shift; my $st = populate(CORE::stat $arg); return $st if defined $st; - my $fh; + return if ref $arg; + # ... maybe $arg is the name of a bareword handle? + my $fh; { - local $!; - no strict 'refs'; - require Symbol; - $fh = \*{ Symbol::qualify( $arg, caller() )}; - return unless defined fileno $fh; - } + local $!; + no strict 'refs'; + require Symbol; + $fh = \*{ Symbol::qualify( $arg, caller() )}; + return unless defined fileno $fh; + } return populate(CORE::stat $fh); } diff --git a/lib/File/stat.t b/lib/File/stat.t index b5475f9d89f7..0175a9304b3f 100644 --- a/lib/File/stat.t +++ b/lib/File/stat.t @@ -191,6 +191,40 @@ SKIP: ok(-p($pstat), "check -p detects a pipe"); } +{ + # GH #23507 + { + package PathObj; + use overload + '""' => sub { $_[0]->to_string }, + fallback => 1; + + sub new { + my $class = shift; + bless { path => $_[0] }, $class + } + + sub to_string { + my $self = shift; + $self->{path} + } + } + + my $good_path = PathObj->new($file); + my $bad_path = PathObj->new('/ no such file'); + + # explicit stringification + isa_ok stat("$good_path"), 'File::stat', 'stat("$good_path")'; + is stat("$bad_path"), undef, 'stat("$bad_path") fails by returning undef'; + # implicit stringification + isa_ok stat($good_path), 'File::stat', 'stat($good_path)'; + is stat($bad_path), undef, 'stat($bad_path) fails by returning undef'; + # and for good measure, unblessed references + is stat(\42), undef, 'stat(\42) fails by returning undef'; + is stat([]), undef, 'stat([]) fails by returning undef'; + is stat({}), undef, 'stat({}) fails by returning undef'; +} + # Testing pretty much anything else is unportable. done_testing;