-l followed by bareword should leave the stack alone
authorFather Chrysostomos <sprout@cpan.org>
Sat, 10 Sep 2011 21:02:45 +0000 (14:02 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 10 Sep 2011 22:49:10 +0000 (15:49 -0700)
$ ln -s /usr/bin/perl bar
$ perl -le' print "bar", -l foo'
1

The -l ate my bar.

It’s this naughty piece of code in doio.c:Perl_my_lstat_flags that is
the culprit:

  if (ckWARN(WARN_IO)) {
      Perl_warner(aTHX_ packWARN(WARN_IO), "Use of -l on filehandle %s",
      GvENAME(cGVOP_gv));
      return (PL_laststatval = -1);
  }

When -l is followed by a bareward, it has no argument on the stack,
but the filetest op itself is a gvop.  That snippet is from the bare-
word-handling code.

So, if warnings are off, it falls through to the argument-on-the-stack
code and pops off something does not belong to it (that belong to the
print, in the example above).

doio.c
t/op/filetest.t

diff --git a/doio.c b/doio.c
index 4626da1..1ce6acc 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -1344,8 +1344,8 @@ Perl_my_lstat_flags(pTHX_ const U32 flags)
        if (ckWARN(WARN_IO)) {
            Perl_warner(aTHX_ packWARN(WARN_IO), "Use of -l on filehandle %s",
                    GvENAME(cGVOP_gv));
-           return (PL_laststatval = -1);
        }
+       return (PL_laststatval = -1);
     }
     else if (PL_laststype != OP_LSTAT
            && (PL_op->op_private & OPpFT_STACKED) && ckWARN(WARN_IO))
index f562646..a6d62ed 100644 (file)
@@ -10,7 +10,7 @@ BEGIN {
 }
 
 use Config;
-plan(tests => 28 + 27*14);
+plan(tests => 29 + 27*14);
 
 ok( -d 'op' );
 ok( -f 'TEST' );
@@ -198,3 +198,9 @@ for my $op (split //, "rwxoRWXOezsfdlpSbctugkTMBAC") {
     is( eval "-r -$op \$ft", "-r",      "stacked overloaded -$op" );
     is( eval "-$op -r \$ft", "-$op",    "overloaded stacked -$op" );
 }
+
+# -l stack corruption: this bug occurred from 5.8 to 5.14
+{
+ push my @foo, "bar", -l baz;
+ is $foo[0], "bar", '-l bareword does not corrupt the stack';
+}