Delicious Perl bug

Discussion in 'Perl Misc' started by Ilya Zakharevich, Jun 1, 2014.

  1. perl -wlpe "s[\w]"

    Probably it is there from Perl v1 (or v2???). I have no clue how to
    fix it (if what I suspect is causing this holds — well, what I suspect
    does not match how this program BEHAVES).

    Enjoy,
    Ilya

    P.S. BTW, I cannot get -d go past line 1 (even with v). Why?
     
    Ilya Zakharevich, Jun 1, 2014
    #1
    1. Advertisements

  2. perl -MO=Deparse -wlpe "s[\w]" shows:

    LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    s/\w/}continue{print or die qq(-p destination: $!\n)/;
    }

    It's pretty clear what happens and why it behaves as it does:

    s[\w] is wrapped in the loop:

    LINE: while (defined($_ = <ARGV>)) { chomp $_; s[\w];}continue{print or die qq(-p destination: $!\n);}

    and when that is parsed, the ; after s[\w] is taken as the start of the
    substitution pattern. That ends at the next ; and the final } closes the
    loop. Perfectly valid perl, but not what was intended.

    That's the kind of gotchas that happens with pure text substitution. The
    C preprocessor has similar issues.

    Theoretically that could be fixed by first compiling the perl fragment
    on the command line and then inserting the finished optree into the
    loop. But I'm not sure if this is possible without unduly restricting
    the semantics.

    I'm also not sure whether it is worthwhile fixing. -e should IMHO only be
    used for very simple programs where an error like this is easy to catch.
    Because there is only one line?

    hp
     
    Peter J. Holzer, Jun 1, 2014
    #2
    1. Advertisements

  3. Ilya Zakharevich

    Tim McDaniel Guest

    You were being way too cute in being too brief and not describing what
    you are thinking.

    perl
    -w warnings
    -l enables automatic line-ending processing: chomp() and set $\
    -p autoprint the result
    -e the program is the next argument

    s[\w]: it took me a moment to realize that you're expecting it to
    cause an error about a bad s///, but it works as a substitute.

    $ perl -wlpe 's[\w]; FROG FROG'
    s3333
    FROG FROG
    3333

    But it works only with ;. Aha!

    $ perl -wlpe 's[\w]! FROG FROG'
    Backslash found where operator expected at -e line 2, near
    ";}continue{print or die qq(-p destination: $!\"
    (Missing operator before \?)
    Unquoted string "n" may clash with future reserved word at -e
    line 2.
    Final $ should be \$ or $name at -e line 1, within string
    syntax error at -e line 2, near ";}continue{print or die qq(-p
    destination: $!"
    (Might be a runaway multi-line !! string starting on line 1)
    Execution of -e aborted due to compilation errors.

    Apparently, where "man perlrun" says

    -p causes Perl to assume the following loop around your program, which
    makes it iterate over filename arguments somewhat like sed:

    LINE:
    while (<>) {
    ... # your program goes here
    } continue {
    print or die "-p destination: $!\n";
    }

    it doesn't mean "it'll be treated like that", it means "it bloody well
    IS wrapped in that, in a very real and literal sense". Similarly

    $ perl -wlpe 's[\w]{ FROG FROG'
    Having no space between pattern and following word is deprecated at -e
    line 2.
    Use of /c modifier is meaningless in s/// at -e line 2.
    Bareword found where operator expected at -e line 2, near ";}continue"
    (Might be a runaway multi-line {} string starting on line 1)
    (Missing operator before ntinue?)
    syntax error at -e line 2, near ";}continue"
    Missing right curly or square bracket at -e line 2, at end of line
    Execution of -e aborted due to compilation errors.

    Is there any way to fix this in general? That is, is there any way to
    have an arbitrary set of Perl code and interpolate it into a code
    skeleton where the interpolation can't break the skeleton somehow?
     
    Tim McDaniel, Jun 2, 2014
    #3
  4. The documentation actually says so.

    [...]
    The good question is "What is 'fix' supposed to mean here?", eg this
    code

    perl -lpe '} while (1) { ++$_'

    behaves exactly like the documentation says it would (when running it
    without an input file, it will 'read something' from stdin and then
    print an endless sequence of ascending numbers).
     
    Rainer Weikusat, Jun 2, 2014
    #4
  5. Wrong. What `perl -d' reports is

    main::(-e:0): BEGIN { require 'perl5db.pl' };LINE: while (<>) {chomp;
    DB<1> v
    1: s[a]
    DB<1>

    So not only `v' does not report anything on the line 0 (which we KNOW
    debugger KNOWS about), but it also does not report anyting for lines 2
    etc.

    Morevoer, doing
    /cont
    locks the debugger more-or-less hard.

    Ilya
     
    Ilya Zakharevich, Jun 4, 2014
    #5
  6. An inner eval{} wrapping the fragment causes an error to reappear. But
    this bit of micro-managing may not make much sense either...

    perl -E ' LINE: while (defined($_ = <ARGV>)) { chomp $_; eval{s[\w];1}
    or die $@;}continue{print or die qq(-p destination: $!\n);}'
     
    Charles DeRykus, Jun 6, 2014
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.