Perl / perl5

đŸȘ The Perl programming language
https://dev.perl.org/perl5/
Other
1.96k stars 555 forks source link

Stacked file tests with -T, -t and/or -B remove too much from the stack #10568

Closed p5pRT closed 12 years ago

p5pRT commented 14 years ago

Migrated from rt.perl.org#77388 (status was 'resolved')

Searchable as RT77388$

p5pRT commented 14 years ago

From p5p@perl.wizbit.be

While writing tests for another bug I discovered a bug in the stacked
file tests. When -T\, -t or -B are used in a stacked file tests then too much is
removed from the stack.

Example​:

#!/usr/bin/perl -l use strict; use warnings; use Test​::More tests => 2;

my $count; my $t; {   $count = 0;   for my $m ("c"\, "d") {   if ($count == 0) {   $t = -t -e $^X ? 0 : "bar";   }   elsif ($count == 1) {   is($m\, "d"\, "-t -e \$^X did not remove too many values
from the stack");   }   $count++;   }

  $count = 0;   for my $m ("e"\, "f") {   if ($count == 0) {   $t = -T -e $^X ? 0 : "baz";   }   elsif ($count == 1) {   is($m\, "f"\, "-T -e \$^X did not remove too many values
from the stack");   }   $count++;   } } __END__ The output of this on blead (81b00ac76d16334c61edb1e9a4a364d00d0db5c6)
and perl-5.10.0​:

1..2 not ok 1 - -t -e $^X did not remove too many values from the stack # Failed test '-t -e $^X did not remove too many values from the stack' # at /tmp/filetest.pl line 12. # got​: 'bar' # expected​: 'd' not ok 2 - -T -e $^X did not remove too many values from the stack # Failed test '-T -e $^X did not remove too many values from the stack' # at /tmp/filetest.pl line 23. # got​: 'baz' # expected​: 'f' # Looks like you failed 2 tests of 2.

A test case that is fatal​:

#!/usr/bin/perl -l

use strict; use warnings; use Test​::More tests => 1;

my $count; my $t; {   $count = 0;   for my $m ("g"\, "h") {   if ($count == 0) {   my $foo;   $foo->{bar} = -T -e $^X ? 0 : "baz";   }   elsif ($count == 1) {   is($m\, "f"\, "-T -e \$^X did not remove too many values
from the stack");   }   $count++;   } } __END__

Output​: 1..1 Use of freed value in iteration at /tmp/filetest.pl line 19. # Looks like your test exited with 2 before it could output anything.

I had a talk with Jan Dubois about this (because he fixed a similar
bug with -u/-g/-k on windows) and this are his notes​:   \ It happens because pp_fttty and pp_fttext don't know about
stacked file tests   \ The problem is that the stacked filetest doesn't leave the
filename on the stack\, it leaves the result of the test only.   \ So the next test in the sequence will pop the result with
STACKED_FTEST_CHECK and either return early with a FALSE value\, or
continue checking   \ The checking will have to rely on PL_laststatval for the next
test in the sequence   \ But the stat buffer doesn't contain the information that -T needs   \ So it always pops something from the stack\, even though there
is nothing there in this case   \ I see. Is it fixable? Or should I create a bug report for it?   \ For pp_ftis is this hard to see because the actual stack logic
is hidden in my_stat() in doio.c (my_stat_flags in 5.12)   \ Please create a bug report\, I'm not sure how you can fix it easily.   \ Because the filename is gone by the time the second stacked
filetest is executed. So how are you going to make the check now?   \ And extending my_stat() is not an option because -T is *expensive*   \ It actually opens the file and reads the first 1024 bytes or
something like that.   \ I'm not sure... the fix could be to disallow -T and -t in
stacked file tests but I don't know how complicated that is..

Best regards\,

Bram

p5pRT commented 14 years ago

From @pjscott

Fairly sure that these should produce the same result​:

$ ./perl -Ilib -wE 'say "Okay" if -w -T "perl.c"' Okay $ ./perl -Ilib -wE 'say "Okay" if -T -w "perl.c"' Use of uninitialized value in -T at -e line 1.

$ ./perl -Ilib -V Summary of my perl5 (revision 5 version 13 subversion 4) configuration​:   Commit id​: f1dcae2ca2c256c755eeec79c4e7d4d5b9cf658f   Platform​:   osname=linux\, osvers=2.6.27.24-170.2.68.fc10.i686\, archname=i686-linux   uname='linux tweety.homeip.net 2.6.27.24-170.2.68.fc10.i686 #1 smp wed may 20 23​:10​:16 edt 2009 i686 i686 i386 gnulinux '   config_args='-des -Dusedevel'   hint=recommended\, useposix=true\, d_sigaction=define   useithreads=undef\, usemultiplicity=undef   useperlio=define\, d_sfio=undef\, uselargefiles=define\, usesocks=undef   use64bitint=undef\, use64bitall=undef\, uselongdouble=undef   usemymalloc=n\, bincompat5005=undef   Compiler​:   cc='cc'\, ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'\,   optimize='-O2'\,   cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'   ccversion=''\, gccversion='4.3.2 20081105 (Red Hat 4.3.2-7)'\, gccosandvers=''   intsize=4\, longsize=4\, ptrsize=4\, doublesize=8\, byteorder=1234   d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=12   ivtype='long'\, ivsize=4\, nvtype='double'\, nvsize=8\, Off_t='off_t'\, lseeksize=8   alignbytes=4\, prototype=define   Linker and Libraries​:   ld='cc'\, ldflags =' -fstack-protector -L/usr/local/lib'   libpth=/usr/local/lib /lib /usr/lib   libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc   perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc   libc=/lib/libc-2.9.so\, so=so\, useshrplib=false\, libperl=libperl.a   gnulibc_version='2.9'   Dynamic Linking​:   dlsrc=dl_dlopen.xs\, dlext=so\, d_dlsymun=undef\, ccdlflags='-Wl\,-E'   cccdlflags='-fPIC'\, lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'

Characteristics of this binary (from libperl)​:   Compile-time options​: PERL_DONT_CREATE_GVSV PERL_MALLOC_WRAP PERL_USE_DEVEL   USE_LARGE_FILES USE_PERLIO USE_PERL_ATOF   Built under linux   Compiled at Sep 5 2010 19​:57​:59   @​INC​:   lib   /usr/local/lib/perl5/site_perl/5.13.4/i686-linux   /usr/local/lib/perl5/site_perl/5.13.4   /usr/local/lib/perl5/5.13.4/i686-linux   /usr/local/lib/perl5/5.13.4   /usr/local/lib/perl5/site_perl   .

p5pRT commented 12 years ago

From @cpansprout

On Mon Aug 23 11​:51​:51 2010\, p5p@​perl.wizbit.be wrote​:

I had a talk with Jan Dubois about this (because he fixed a similar
bug with -u/-g/-k on windows) and this are his notes​: \ It happens because pp_fttty and pp_fttext don't know about
stacked file tests \ The problem is that the stacked filetest doesn't leave the
filename on the stack\, it leaves the result of the test only. \ So the next test in the sequence will pop the result with
STACKED_FTEST_CHECK and either return early with a FALSE value\, or
continue checking \ The checking will have to rely on PL_laststatval for the next
test in the sequence \ But the stat buffer doesn't contain the information that -T needs \ So it always pops something from the stack\, even though there
is nothing there in this case \ I see. Is it fixable? Or should I create a bug report for it? \ For pp_ftis is this hard to see because the actual stack logic
is hidden in my_stat() in doio.c (my_stat_flags in 5.12) \ Please create a bug report\, I'm not sure how you can fix it easily. \ Because the filename is gone by the time the second stacked
filetest is executed. So how are you going to make the check now?

The file name is in PL_statname. The last gv is in PL_statgv. -T and -B can already handle *_. They just need to be taught to do so in stacked mode instead of popping something off the stack.

(There does seem to be another bug\, though. The code is not setting PL_laststype when called with a gv. And I think a nonexistent file name will cause the internal stat status to get out of sync\, as PL_last_stat_val and PL_statcache are not set until after the file is opened\, but PL_laststype is set before. Ouch\, there is so much wrong with this code!)

\ And extending my_stat() is not an option because -T is *expensive* \ It actually opens the file and reads the first 1024 bytes or
something like that. \ I'm not sure... the fix could be to disallow -T and -t in
stacked file tests but I don't know how complicated that is..

But -t is difficult. -r -w $foo is documented as being equivalent to -r $foo && -w _. But -t doesn’t work with _. We could make -t use _ when stacked\, which would be silly. I can’t think of a case where stacked -t is actually useful\, which makes it hard to decide how it should work.

Actually\, forget half of that. -t could use PL_statgv\, too. We just need to document that -t -r is not exactly equivalent to -r && -t _.

Should -t -r "filename" be an error\, or equivalent to -r "filename" && -t "filename"?

--

Father Chrysostomos

p5pRT commented 12 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 12 years ago

From @cpansprout

On Wed Jan 11 22​:33​:40 2012\, sprout wrote​:

On Mon Aug 23 11​:51​:51 2010\, p5p@​perl.wizbit.be wrote​:

I had a talk with Jan Dubois about this (because he fixed a similar
bug with -u/-g/-k on windows) and this are his notes​: \ It happens because pp_fttty and pp_fttext don't know about
stacked file tests \ The problem is that the stacked filetest doesn't leave the
filename on the stack\, it leaves the result of the test only. \ So the next test in the sequence will pop the result with
STACKED_FTEST_CHECK and either return early with a FALSE value\, or
continue checking \ The checking will have to rely on PL_laststatval for the next
test in the sequence \ But the stat buffer doesn't contain the information that -T needs \ So it always pops something from the stack\, even though there
is nothing there in this case \ I see. Is it fixable? Or should I create a bug report for it? \ For pp_ftis is this hard to see because the actual stack logic
is hidden in my_stat() in doio.c (my_stat_flags in 5.12) \ Please create a bug report\, I'm not sure how you can fix it easily. \ Because the filename is gone by the time the second stacked
filetest is executed. So how are you going to make the check now?

The file name is in PL_statname. The last gv is in PL_statgv. -T and -B can already handle *_. They just need to be taught to do so in stacked mode instead of popping something off the stack.

(There does seem to be another bug\, though. The code is not setting PL_laststype when called with a gv. And I think a nonexistent file name will cause the internal stat status to get out of sync\, as PL_last_stat_val and PL_statcache are not set until after the file is opened\, but PL_laststype is set before. Ouch\, there is so much wrong with this code!)

\ And extending my_stat() is not an option because -T is *expensive* \ It actually opens the file and reads the first 1024 bytes or
something like that. \ I'm not sure... the fix could be to disallow -T and -t in
stacked file tests but I don't know how complicated that is..

But -t is difficult. -r -w $foo is documented as being equivalent to -r $foo && -w _. But -t doesn’t work with _. We could make -t use _ when stacked\, which would be silly. I can’t think of a case where stacked -t is actually useful\, which makes it hard to decide how it should work.

Actually\, forget half of that. -t could use PL_statgv\, too. We just need to document that -t -r is not exactly equivalent to -r && -t _.

Should -t -r "filename" be an error\, or equivalent to -r "filename" && -t "filename"?

Except that can’t really work either\, because what would -r -t do? After all\, -t doesn’t *set* the stat buffer\, either.

I propose we make stacked -t an error in 5.16. It has never worked\, it’s not clear how it should work\, and if we try to make it do something illogical we’ll be stuck ‘supporting’ that behaviour.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

On Wed Jan 11 22​:33​:40 2012\, sprout wrote​:

On Mon Aug 23 11​:51​:51 2010\, p5p@​perl.wizbit.be wrote​:

I had a talk with Jan Dubois about this (because he fixed a similar
bug with -u/-g/-k on windows) and this are his notes​: \ It happens because pp_fttty and pp_fttext don't know about
stacked file tests \ The problem is that the stacked filetest doesn't leave the
filename on the stack\, it leaves the result of the test only. \ So the next test in the sequence will pop the result with
STACKED_FTEST_CHECK and either return early with a FALSE value\, or
continue checking \ The checking will have to rely on PL_laststatval for the next
test in the sequence \ But the stat buffer doesn't contain the information that -T needs \ So it always pops something from the stack\, even though there
is nothing there in this case \ I see. Is it fixable? Or should I create a bug report for it? \ For pp_ftis is this hard to see because the actual stack logic
is hidden in my_stat() in doio.c (my_stat_flags in 5.12) \ Please create a bug report\, I'm not sure how you can fix it easily. \ Because the filename is gone by the time the second stacked
filetest is executed. So how are you going to make the check now?

The file name is in PL_statname. The last gv is in PL_statgv. -T and -B can already handle *_. They just need to be taught to do so in stacked mode instead of popping something off the stack.

That part is fixed in commit ba8182f85.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

On Wed Jan 11 22​:33​:40 2012\, sprout wrote​:

(There does seem to be another bug\, though. The code is not setting PL_laststype when called with a gv.

That part is fixed with 5731662.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

On Thu Jan 12 13​:30​:10 2012\, sprout wrote​:

Except that can’t really work either\, because what would -r -t do? After all\, -t doesn’t *set* the stat buffer\, either.

I propose we make stacked -t an error in 5.16. It has never worked\, it’s not clear how it should work\, and if we try to make it do something illogical we’ll be stuck ‘supporting’ that behaviour.

But maybe later we could make -t work with _.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

On Wed Jan 11 22​:33​:40 2012\, sprout wrote​:

And I think a nonexistent file name will cause the internal stat status to get out of sync\, as PL_last_stat_val and PL_statcache are not set until after the file is opened\, but PL_laststype is set before.

And that part is fixed in commit ad2d99e3. See also #4253.

The only thing left in this ticket is stacked -t.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

On Sat Jan 14 00​:58​:12 2012\, sprout wrote​:

On Thu Jan 12 13​:30​:10 2012\, sprout wrote​:

Except that can’t really work either\, because what would -r -t do? After all\, -t doesn’t *set* the stat buffer\, either.

I propose we make stacked -t an error in 5.16. It has never worked\, it’s not clear how it should work\, and if we try to make it do something illogical we’ll be stuck ‘supporting’ that behaviour.

But maybe later we could make -t work with _.

I was about to make stacked -t a compile time error\, when I realised that it would break objects with -X overloading\, which currently *do* work with stacked -t.

So I realised the real problem​: When overloading is not present\, the -r in -r -w foo uses _. When overloading is present\, -w arranges for -r to receive the same argument.

So it only makes sense to me to use the latter mechanism for stacked -t.

Using the former still makes sense for other filetest operators\, because -r -w foo should only do one stat\, not two.

(Is anybody reading this?)

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

On Fri Jan 20 14​:13​:32 2012\, sprout wrote​:

On Sat Jan 14 00​:58​:12 2012\, sprout wrote​:

On Thu Jan 12 13​:30​:10 2012\, sprout wrote​:

Except that can’t really work either\, because what would -r -t do? After all\, -t doesn’t *set* the stat buffer\, either.

I propose we make stacked -t an error in 5.16. It has never worked\, it’s not clear how it should work\, and if we try to make it do something illogical we’ll be stuck ‘supporting’ that behaviour.

But maybe later we could make -t work with _.

I was about to make stacked -t a compile time error\, when I realised that it would break objects with -X overloading\, which currently *do* work with stacked -t.

So I realised the real problem​: When overloading is not present\, the -r in -r -w foo uses _. When overloading is present\, -w arranges for -r to receive the same argument.

So it only makes sense to me to use the latter mechanism for stacked -t.

Using the former still makes sense for other filetest operators\, because -r -w foo should only do one stat\, not two.

On the other hand\, -t -r -w should still work\, so -r and -w should *always* pass the filehandle or file name through\, but check the stacked flag to see whether it should actually be used.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @rjbs

* Father Chrysostomos via RT \perlbug\-followup@​perl\.org [2012-01-20T17​:13​:33]

(Is anybody reading this?)

Yes\, and it's an area I've grumbled through myself. I'll try to say something tomorrow. Tonight is crammed.

-- rjbs

p5pRT commented 12 years ago

From @cpansprout

On Fri Jan 20 16​:25​:43 2012\, perl.p5p@​rjbs.manxome.org wrote​:

* Father Chrysostomos via RT \perlbug\-followup@​perl\.org [2012-01- 20T17​:13​:33]

(Is anybody reading this?)

Yes\, and it's an area I've grumbled through myself. I'll try to say something tomorrow.

And when you do so\, can you consider the attached patch? It just makes -t -e -f -l -o N dwim\, because the N argument is now passed down to each op. Those that are capable will use the last stat buffer. Those that are not (-t -T -B) will use the argument.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

Inline Patch ```diff diff --git a/doio.c b/doio.c index 08a15b7..f2c84a4 100644 --- a/doio.c +++ b/doio.c @@ -1292,14 +1292,13 @@ Perl_my_stat_flags(pTHX_ const U32 flags) report_evil_fh(gv); return -1; } - else if (PL_op->op_private & OPpFT_STACKED) { - return PL_laststatval; - } else { - SV* const sv = POPs; + SV* const sv = PL_op->op_private & OPpFT_STACKING ? TOPs : POPs; + PUTBACK; + if (PL_op->op_private & OPpFT_STACKED) return PL_laststatval; + else { const char *s; STRLEN len; - PUTBACK; if ((gv = MAYBE_DEREF_GV_flags(sv,flags))) { goto do_fstat; } @@ -1318,6 +1317,7 @@ Perl_my_stat_flags(pTHX_ const U32 flags) if (PL_laststatval < 0 && ckWARN(WARN_NEWLINE) && strchr(s, '\n')) Perl_warner(aTHX_ packWARN(WARN_NEWLINE), PL_warn_nl, "stat"); return PL_laststatval; + } } } @@ -1345,7 +1345,9 @@ Perl_my_lstat_flags(pTHX_ const U32 flags) } return -1; } - else if (PL_op->op_private & OPpFT_STACKED) { + sv = PL_op->op_private & OPpFT_STACKING ? TOPs : POPs; + PUTBACK; + if (PL_op->op_private & OPpFT_STACKED) { if (PL_laststype != OP_LSTAT) Perl_croak(aTHX_ no_prev_lstat); return PL_laststatval; @@ -1353,8 +1355,6 @@ Perl_my_lstat_flags(pTHX_ const U32 flags) PL_laststype = OP_LSTAT; PL_statgv = NULL; - sv = POPs; - PUTBACK; file = SvPV_flags_const_nolen(sv, flags); sv_setpv(PL_statname,file); PL_laststatval = PerlLIO_lstat(file,&PL_statcache); diff --git a/pp_sys.c b/pp_sys.c index 20a34ac..33ee553 100644 --- a/pp_sys.c +++ b/pp_sys.c @@ -2895,14 +2895,48 @@ PP(pp_stat) RETURN; } +/* If the next filetest is stacked up with this one + (PL_op->op_private & OPpFT_STACKING), we leave + the original argument on the stack for success, + and skip the stacked operators on failure. + The next few macros/functions take care of this. +*/ + +static OP * +S_ft_stacking_return_false(pTHX_ SV *ret) { + dSP; + OP *next = NORMAL; + while (OP_IS_FILETEST(next->op_type) + && next->op_private & OPpFT_STACKED) + next = next->op_next; + if (PL_op->op_flags & OPf_REF) PUSHs(ret); + else SETs(ret); + PUTBACK; + return next; +} + +#define FT_RETURN_FALSE(X) \ + STMT_START { \ + if (PL_op->op_private & OPpFT_STACKING) \ + return S_ft_stacking_return_false(aTHX_ X); \ + RETURNX(PUSHs(X)); \ + } STMT_END +#define FT_RETURN_TRUE(X) \ + RETURNX((void)(PL_op->op_private & OPpFT_STACKING || PUSHs(X))) + +#define FT_RETURNNO FT_RETURN_FALSE(&PL_sv_no) +#define FT_RETURNUNDEF FT_RETURN_FALSE(&PL_sv_undef) +#define FT_RETURNYES FT_RETURN_TRUE(&PL_sv_yes) + #define tryAMAGICftest_MG(chr) STMT_START { \ if ( (SvFLAGS(TOPs) & (SVf_ROK|SVs_GMG)) \ - && PL_op->op_flags & OPf_KIDS \ - && S_try_amagic_ftest(aTHX_ chr)) \ - return NORMAL; \ + && PL_op->op_flags & OPf_KIDS) { \ + OP *next = S_try_amagic_ftest(aTHX_ chr); \ + if (next) return next; \ + } \ } STMT_END -STATIC bool +STATIC OP * S_try_amagic_ftest(pTHX_ char chr) { dVAR; dSP; @@ -2919,33 +2953,17 @@ S_try_amagic_ftest(pTHX_ char chr) { ftest_amg, AMGf_unary); if (!tmpsv) - return FALSE; + return NULL; SPAGAIN; - if (PL_op->op_private & OPpFT_STACKING) { - if (SvTRUE(tmpsv)) - /* leave the object alone */ - return TRUE; - } - - SETs(tmpsv); - PUTBACK; - return TRUE; + if (SvTRUE(tmpsv)) FT_RETURN_TRUE(tmpsv); + FT_RETURN_FALSE(tmpsv); } - return FALSE; + return NULL; } -/* This macro is used by the stacked filetest operators : - * if the previous filetest failed, short-circuit and pass its value. - * Else, discard it from the stack and continue. --rgs - */ -#define STACKED_FTEST_CHECK if (PL_op->op_private & OPpFT_STACKED) { \ - if (!SvTRUE(TOPs)) { RETURN; } \ - else { (void)POPs; PUTBACK; } \ - } - PP(pp_ftrread) { dVAR; @@ -2981,8 +2999,6 @@ PP(pp_ftrread) } tryAMAGICftest_MG(opchar); - STACKED_FTEST_CHECK; - switch (PL_op->op_type) { case OP_FTRREAD: #if !(defined(HAS_ACCESS) && defined(R_OK)) @@ -3062,10 +3078,10 @@ PP(pp_ftrread) result = my_stat_flags(0); SPAGAIN; if (result < 0) - RETPUSHUNDEF; + FT_RETURNUNDEF; if (cando(stat_mode, effective, &PL_statcache)) - RETPUSHYES; - RETPUSHNO; + FT_RETURNYES; + FT_RETURNNO; } PP(pp_ftis) @@ -3085,14 +3101,12 @@ PP(pp_ftis) } tryAMAGICftest_MG(opchar); - STACKED_FTEST_CHECK; - result = my_stat_flags(0); SPAGAIN; if (result < 0) - RETPUSHUNDEF; + FT_RETURNUNDEF; if (op_type == OP_FTIS) - RETPUSHYES; + FT_RETURNYES; { /* You can't dTARGET inside OP_FTIS, because you'll get "panic: pad_sv po" - the op is not flagged to have a target. */ @@ -3100,23 +3114,28 @@ PP(pp_ftis) switch (op_type) { case OP_FTSIZE: #if Off_t_size > IVSIZE - PUSHn(PL_statcache.st_size); + sv_setnv(TARG, (NV)PL_statcache.st_size); #else - PUSHi(PL_statcache.st_size); + sv_setiv(TARG, (IV)PL_statcache.st_size); #endif break; case OP_FTMTIME: - PUSHn( (((NV)PL_basetime - PL_statcache.st_mtime)) / 86400.0 ); + sv_setnv(TARG, + ((NV)PL_basetime - PL_statcache.st_mtime) / 86400.0 ); break; case OP_FTATIME: - PUSHn( (((NV)PL_basetime - PL_statcache.st_atime)) / 86400.0 ); + sv_setnv(TARG, + ((NV)PL_basetime - PL_statcache.st_atime) / 86400.0 ); break; case OP_FTCTIME: - PUSHn( (((NV)PL_basetime - PL_statcache.st_ctime)) / 86400.0 ); + sv_setnv(TARG, + ((NV)PL_basetime - PL_statcache.st_ctime) / 86400.0 ); break; } + SvSETMAGIC(TARG); + if (SvTRUE_nomg(TARG)) FT_RETURN_TRUE(TARG); + else FT_RETURN_FALSE(TARG); } - RETURN; } PP(pp_ftrowned) @@ -3142,93 +3161,91 @@ PP(pp_ftrowned) } tryAMAGICftest_MG(opchar); - STACKED_FTEST_CHECK; - /* I believe that all these three are likely to be defined on most every system these days. */ #ifndef S_ISUID if(PL_op->op_type == OP_FTSUID) { - if ((PL_op->op_flags & OPf_REF) == 0 && (PL_op->op_private & OPpFT_STACKED) == 0) + if ((PL_op->op_flags & OPf_REF) == 0 && !(PL_op->op_private & OPpFT_STACKING)) (void) POPs; - RETPUSHNO; + FT_RETURNNO; } #endif #ifndef S_ISGID if(PL_op->op_type == OP_FTSGID) { - if ((PL_op->op_flags & OPf_REF) == 0 && (PL_op->op_private & OPpFT_STACKED) == 0) + if ((PL_op->op_flags & OPf_REF) == 0 && !(PL_op->op_private & OPpFT_STACKING)) (void) POPs; - RETPUSHNO; + FT_RETURNNO; } #endif #ifndef S_ISVTX if(PL_op->op_type == OP_FTSVTX) { - if ((PL_op->op_flags & OPf_REF) == 0 && (PL_op->op_private & OPpFT_STACKED) == 0) + if ((PL_op->op_flags & OPf_REF) == 0 && !(PL_op->op_private & OPpFT_STACKING)) (void) POPs; - RETPUSHNO; + FT_RETURNNO; } #endif result = my_stat_flags(0); SPAGAIN; if (result < 0) - RETPUSHUNDEF; + FT_RETURNUNDEF; switch (PL_op->op_type) { case OP_FTROWNED: if (PL_statcache.st_uid == PL_uid) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTEOWNED: if (PL_statcache.st_uid == PL_euid) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTZERO: if (PL_statcache.st_size == 0) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTSOCK: if (S_ISSOCK(PL_statcache.st_mode)) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTCHR: if (S_ISCHR(PL_statcache.st_mode)) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTBLK: if (S_ISBLK(PL_statcache.st_mode)) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTFILE: if (S_ISREG(PL_statcache.st_mode)) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTDIR: if (S_ISDIR(PL_statcache.st_mode)) - RETPUSHYES; + FT_RETURNYES; break; case OP_FTPIPE: if (S_ISFIFO(PL_statcache.st_mode)) - RETPUSHYES; + FT_RETURNYES; break; #ifdef S_ISUID case OP_FTSUID: if (PL_statcache.st_mode & S_ISUID) - RETPUSHYES; + FT_RETURNYES; break; #endif #ifdef S_ISGID case OP_FTSGID: if (PL_statcache.st_mode & S_ISGID) - RETPUSHYES; + FT_RETURNYES; break; #endif #ifdef S_ISVTX case OP_FTSVTX: if (PL_statcache.st_mode & S_ISVTX) - RETPUSHYES; + FT_RETURNYES; break; #endif } - RETPUSHNO; + FT_RETURNNO; } PP(pp_ftlink) @@ -3238,15 +3255,14 @@ PP(pp_ftlink) I32 result; tryAMAGICftest_MG('l'); - STACKED_FTEST_CHECK; result = my_lstat_flags(0); SPAGAIN; if (result < 0) - RETPUSHUNDEF; + FT_RETURNUNDEF; if (S_ISLNK(PL_statcache.st_mode)) - RETPUSHYES; - RETPUSHNO; + FT_RETURNYES; + FT_RETURNNO; } PP(pp_fttty) @@ -3260,12 +3276,10 @@ PP(pp_fttty) tryAMAGICftest_MG('t'); - STACKED_FTEST_CHECK; - if (PL_op->op_flags & OPf_REF) gv = cGVOP_gv; else { - SV *tmpsv = POPs; + SV *tmpsv = PL_op->op_private & OPpFT_STACKING ? TOPs : POPs; if (!(gv = MAYBE_DEREF_GV_nomg(tmpsv))) { name = SvPV_nomg(tmpsv, namelen); gv = gv_fetchpvn_flags(name, namelen, SvUTF8(tmpsv), SVt_PVIO); @@ -3277,10 +3291,10 @@ PP(pp_fttty) else if (name && isDIGIT(*name)) fd = atoi(name); else - RETPUSHUNDEF; + FT_RETURNUNDEF; if (PerlLIO_isatty(fd)) - RETPUSHYES; - RETPUSHNO; + FT_RETURNYES; + FT_RETURNNO; } #if defined(atarist) /* this will work with atariST. Configure will @@ -3307,16 +3321,15 @@ PP(pp_fttext) tryAMAGICftest_MG(PL_op->op_type == OP_FTTEXT ? 'T' : 'B'); - STACKED_FTEST_CHECK; - if (PL_op->op_flags & OPf_REF) { gv = cGVOP_gv; EXTEND(SP, 1); } - else if (PL_op->op_private & OPpFT_STACKED) - gv = PL_defgv; - else sv = POPs, gv = MAYBE_DEREF_GV_nomg(sv); + else { + sv = PL_op->op_private & OPpFT_STACKING ? TOPs : POPs; + gv = MAYBE_DEREF_GV_nomg(sv); + } if (gv) { if (gv == PL_defgv) { @@ -3340,12 +3353,12 @@ PP(pp_fttext) DIE(aTHX_ "-T and -B not implemented on filehandles"); PL_laststatval = PerlLIO_fstat(PerlIO_fileno(IoIFP(io)), &PL_statcache); if (PL_laststatval < 0) - RETPUSHUNDEF; + FT_RETURNUNDEF; if (S_ISDIR(PL_statcache.st_mode)) { /* handle NFS glitch */ if (PL_op->op_type == OP_FTTEXT) - RETPUSHNO; + FT_RETURNNO; else - RETPUSHYES; + FT_RETURNYES; } if (PerlIO_get_cnt(IoIFP(io)) <= 0) { i = PerlIO_getc(IoIFP(io)); @@ -3353,7 +3366,7 @@ PP(pp_fttext) (void)PerlIO_ungetc(IoIFP(io),i); } if (PerlIO_get_cnt(IoIFP(io)) <= 0) /* null file is anything */ - RETPUSHYES; + FT_RETURNYES; len = PerlIO_get_bufsiz(IoIFP(io)); s = (STDCHAR *) PerlIO_get_base(IoIFP(io)); /* sfio can have large buffers - limit to 512 */ @@ -3364,7 +3377,7 @@ PP(pp_fttext) SETERRNO(EBADF,RMS_IFI); report_evil_fh(gv); SETERRNO(EBADF,RMS_IFI); - RETPUSHUNDEF; + FT_RETURNUNDEF; } } else { @@ -3379,21 +3392,21 @@ PP(pp_fttext) if (ckWARN(WARN_NEWLINE) && strchr(SvPV_nolen_const(PL_statname), '\n')) Perl_warner(aTHX_ packWARN(WARN_NEWLINE), PL_warn_nl, "open"); - RETPUSHUNDEF; + FT_RETURNUNDEF; } PL_laststype = OP_STAT; PL_laststatval = PerlLIO_fstat(PerlIO_fileno(fp), &PL_statcache); if (PL_laststatval < 0) { (void)PerlIO_close(fp); - RETPUSHUNDEF; + FT_RETURNUNDEF; } PerlIO_binmode(aTHX_ fp, '<', O_BINARY, NULL); len = PerlIO_read(fp, tbuf, sizeof(tbuf)); (void)PerlIO_close(fp); if (len <= 0) { if (S_ISDIR(PL_statcache.st_mode) && PL_op->op_type == OP_FTTEXT) - RETPUSHNO; /* special case NFS directories */ - RETPUSHYES; /* null file is anything */ + FT_RETURNNO; /* special case NFS directories */ + FT_RETURNYES; /* null file is anything */ } s = tbuf; } @@ -3447,9 +3460,9 @@ PP(pp_fttext) } if ((odd * 3 > len) == (PL_op->op_type == OP_FTTEXT)) /* allow 1/3 odd */ - RETPUSHNO; + FT_RETURNNO; else - RETPUSHYES; + FT_RETURNYES; } /* File calls. */ diff --git a/t/op/filetest_stack_ok.t b/t/op/filetest_stack_ok.t index c89428c..6be383a 100644 --- a/t/op/filetest_stack_ok.t +++ b/t/op/filetest_stack_ok.t @@ -36,10 +36,6 @@ for my $op (@ops) { $t = eval "-$op -e \$^X" ? 0 : "bar"; } elsif ($count == 1) { - local $TODO; - if ($op eq 't') { - $TODO = "[perl #77388] stacked file test does not work with -$op"; - } is($m, "d", "-$op -e \$^X did not remove too many values from the stack"); } $count++; diff --git a/t/op/filetest_t.t b/t/op/filetest_t.t index 3508564..cbbdbc6 100644 --- a/t/op/filetest_t.t +++ b/t/op/filetest_t.t @@ -8,7 +8,7 @@ BEGIN { use strict; -plan 2; +plan 6; my($dev_tty, $dev_null) = qw(/dev/tty /dev/null); ($dev_tty, $dev_null) = qw(con nul ) if $^O =~ /^(MSWin32|os2)$/; @@ -23,9 +23,13 @@ SKIP: { skip("'$tt_dev' is probably not a terminal") if $tt_dev !~ m/^_(tt|ft|rt)/i; } ok(-t $tty, "'$dev_tty' is a TTY"); + ok(-t -e $tty, "'$dev_tty' is a TTY (with -t -e)"); + ok(-e -t $tty, "'$dev_tty' is a TTY (with -e -t)"); } SKIP: { open(my $null, "<", $dev_null) or skip("Can't open null device '$dev_null': $!"); ok(!-t $null, "'$dev_null' is not a TTY"); + ok(!-t -e $null, "'$dev_null' is not a TTY (with -t -e)"); + ok(!-e -t $null, "'$dev_null' is not a TTY (with -e -t)"); } ```
p5pRT commented 12 years ago

From @cpansprout

On Sat Jan 21 17​:04​:10 2012\, sprout wrote​:

On Fri Jan 20 16​:25​:43 2012\, perl.p5p@​rjbs.manxome.org wrote​:

* Father Chrysostomos via RT \perlbug\-followup@&#8203;perl\.org [2012-01- 20T17​:13​:33]

(Is anybody reading this?)

Yes\, and it's an area I've grumbled through myself. I'll try to say something tomorrow.

And when you do so\, can you consider the attached patch? It just makes -t -e -f -l -o N dwim\, because the N argument is now passed down to each op. Those that are capable will use the last stat buffer. Those that are not (-t -T -B) will use the argument.

Except that patch needs a bit of tweaking to make -r -t dwim\, but my point is that this is doable before 5.16.

--

Father Chrysostomos

p5pRT commented 12 years ago

From @rjbs

* Father Chrysostomos via RT \perlbug\-followup@&#8203;perl\.org [2012-01-21T20​:04​:11]

On Fri Jan 20 16​:25​:43 2012\, perl.p5p@​rjbs.manxome.org wrote​:

* Father Chrysostomos via RT \perlbug\-followup@&#8203;perl\.org [2012-01- 20T17​:13​:33]

(Is anybody reading this?)

Yes\, and it's an area I've grumbled through myself. I'll try to say something tomorrow.

And when you do so\, can you consider the attached patch? It just makes -t -e -f -l -o N dwim\, because the N argument is now passed down to each op. Those that are capable will use the last stat buffer. Those that are not (-t -T -B) will use the argument.

This seems like a change for the better to me. Thanks for your patience.

-- rjbs

p5pRT commented 12 years ago

From @cpansprout

On Mon Jan 23 18​:28​:42 2012\, perl.p5p@​rjbs.manxome.org wrote​:

* Father Chrysostomos via RT \perlbug\-followup@&#8203;perl\.org [2012-01- 21T20​:04​:11]

On Fri Jan 20 16​:25​:43 2012\, perl.p5p@​rjbs.manxome.org wrote​:

* Father Chrysostomos via RT \perlbug\-followup@&#8203;perl\.org [2012-01- 20T17​:13​:33]

(Is anybody reading this?)

Yes\, and it's an area I've grumbled through myself. I'll try to say something tomorrow.

And when you do so\, can you consider the attached patch? It just makes -t -e -f -l -o N dwim\, because the N argument is now passed down to each op. Those that are capable will use the last stat buffer. Those that are not (-t -T -B) will use the argument.

This seems like a change for the better to me. Thanks for your patience.

A modified version of it is now applied as 8db8f6b.

--

Father Chrysostomos

p5pRT commented 12 years ago

@cpansprout - Status changed from 'open' to 'resolved'