in reply to Re: Slurping search-replace patterns from a file
in thread RESOLVED: Slurping search-replace patterns from a file

Please don't recommend something like that without mentioning that the /ee modifier calls eval and thus opens the door for execution of arbitrary code.

A safe alternative might be String::Interpolate, but it might require a bit more work.

Update: if it's not obvious what the unsafe part is, look at this:

my $x = 'abc'; my $evil = '"; print "evil stuff here\n"; "'; $x =~s/a(bc)/qq{"$evil"}/ee;

Instead of the print... arbitrary perl code can be executed.

Replies are listed 'Best First'.
Re^3: Slurping search-replace patterns from a file
by gone2015 (Deacon) on Oct 14, 2008 at 17:21 UTC

    Since the issue is the interpolation of the replacement string, can you not stamp on '$' and '@', leaving only '$1' et al ? That is:

    use strict ; use warnings ; while (<DATA>) { my ($pat, $repl) = (split '/') [1, 2]; # Escape $ and @ preceded by an even number of '\', except for $1 +etc. $repl =~ s/(?<!\\)((?:\\\\)*(?:\$(?!\d)|\@))/\\$1/g ; my $e = "\$s =~ s/$pat/$repl/" ; my $s = "foo"; print "$e '$s' -> " ; eval $e ; die $@ if $@ ; print "'$s'\n" ; } __DATA__ s/foo/bar/ s/(fo)o/bar$1/ s/oo/\${system "echo hello sailor !"}/ s/oo/\\${system "echo hello sailor !"}/ s/oo/\\\${system "echo hello sailor !"}/ s/oo/\\\\${system "echo hello sailor !"}/ s/oo/\\\\\${system "echo hello sailor !"}/ s/oo/@{system "echo hello sailor !"}/ s/oo/\@{system "echo hello sailor !"}/ s/oo/\\@{system "echo hello sailor !"}/
    Noting that you don't want to "activate" '\$' or '\@' by inserting '\'.

    Hope I didn't miss anything...

      Hope I didn't miss anything...

      That's the crucial point: You never know. Perl is a language with a very complex syntax (compared to all other programming languages that I know of) that you can basically never be sure if you approach things in this way.

      I thought I was quite confident with Perl's syntax, until I found out that you can have whitespaces between the sigil and the variable, and that even works in string interpolation:

      $ perl -wle 'my $x = 3; print "x: $ x"' x: 3

      I certainly didn't expect that.

      What I learned from this is to never assume that you know every detail of Perl syntax, so I won't be sure that I've covered all corner cases. Can you be?

        What I learned from this is to never assume that you know every detail of Perl syntax, so I won't be sure that I've covered all corner cases. Can you be?

        I would not presume.

        AFAIK the only characters that trigger interpolation are '$' and '@'. But, as you say, with Perl it's unsafe to assume that anything can be depended on.

        However, if we can trust that much, then escaping '$' unless it's followed by a digit only lets past stuff which is supposed to be safe. And escaping '@' unconditionally seems to cover that. Unless there's some other magic that throws the escaping mechansm.

        <sigh>

        I suppose one could fall back on a hand affair:

        use strict ; use warnings ; while (<DATA>) { my ($pat, $repl) = (split '/') [1, 2]; my $s = "foo" ; printf "%40s '%s' -> ", "/$pat/$repl/", $s ; my @trap = $s =~ m/$pat/ ; $repl =~ s/(?<!\\)((?:\\\\)*)\$([1-9])/(defined($1) ? $1 : '') .(defined($trap[$2-1]) ? $tra +p[$2-1] : '')/eg ; $s =~ s/$pat/$repl/ ; print "'$s'\n" ; } __DATA__ s/foo/bar/ s/(fo)o/bar$1/ s/(fo)o/bar\$1/ s/(fo)o/bar\\$1/ s/oo/${system "echo hello sailor !"}/ s/oo/@{system "echo hello sailor !"}/
        which only attempts to simulate '$1'..'$9' -- but that may be sufficient. Of course, String::Interpolate may well do a more complete job.

        Unless, of course, there's some other gotcha...