Skip to content

stacked filetest ops stat unexpected “filename containing newline” #18293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mgkuhn opened this issue Nov 5, 2020 · 2 comments · Fixed by #18307
Closed

stacked filetest ops stat unexpected “filename containing newline” #18293

mgkuhn opened this issue Nov 5, 2020 · 2 comments · Fixed by #18307

Comments

@mgkuhn
Copy link

mgkuhn commented Nov 5, 2020

Module: core

Description

The following MWE script unexpectedly outputs a warning about an “unsuccessful stat on filename containing newline”:

#!/usr/bin/perl
use 5.014;
use warnings;
use HTTP::Tiny;

HTTP::Tiny->new->head("https://www.perl.org/");
if ('a' =~ /^(.)$/) {
    if (-f -r $1) {
        say "a";
    }
}

A workaround is to replace -f -r $1 with -r $1 && -f _. This is in contradiction to the documentation in man perlfunc, which states that the former is just “a form of purely syntactic sugar” for the latter.

Steps to Reproduce

Run the above script on Ubuntu Linux (e.g., 20.04).

Actual behavior

$ ./bug.pl 
Unsuccessful stat on filename containing newline at ./bug.pl line 8.

Expected behavior

$ ./bug.pl 
$ touch a
$ ./bug.pl 
a

Perl should try to stat the filename a instead of any “filename containing newline”,
and output a if and only if file a exists and is readable.

Perl configuration

I encountered this behaviour on both Perl 5.30.0 as included in Ubuntu Linux 20.04 (x86_64), as well as Perl 5.22.1 as included in Ubuntu Linux 16.04 (x86_64).

@hvds
Copy link
Contributor

hvds commented Nov 6, 2020

The use of HTTP::Tiny appears to be a partial red herring; without it I see:

% ${PERL} -wle 'if ("a" =~ /^(.)$/) { if (-f -r $1) { print "ok" } }'
Use of uninitialized value $1 in -r at -e line 1.
% ${PERL} -wle 'if ("a" =~ /^(.)$/) { print "-$1-"; if (-f -r $1) { print "ok" } }'
-a-
% touch a ; ${PERL} -wle 'if ("a" =~ /^(.)$/) { print "-$1-"; if (-f -r $1) { print "ok" } }'
-a-
ok
% 

.. so somehow -f -r $1 is picking up something wrong for $1 if it hasn't been read first.

@hvds
Copy link
Contributor

hvds commented Nov 6, 2020

Hmm, it correctly reaches op.c:S_try_amagic_ftest, but in:

    if (!(PL_op->op_private & OPpFT_STACKING)) SvGETMAGIC(arg);

the first stacked opcode has OPpFT_STACKING, so we don't perform the getmagic.

We need a test that will be true on the first of a stack of filetests, and false on the rest; however this test will be true on the last of a stack, and false on the rest. Not sure how best to fix that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants