a4ac56
From 3f8a98327dfdb171bd6e447fec23721b0e74c7a6 Mon Sep 17 00:00:00 2001
a4ac56
From: Zefram <zefram@fysh.org>
a4ac56
Date: Sun, 19 Nov 2017 09:15:53 +0000
a4ac56
Subject: [PATCH] fix tainting of s/// with overloaded replacement
a4ac56
MIME-Version: 1.0
a4ac56
Content-Type: text/plain; charset=UTF-8
a4ac56
Content-Transfer-Encoding: 8bit
a4ac56
a4ac56
The substitution code was trying to track the taintedness of the
a4ac56
replacement string itself, but it didn't account for the replacement
a4ac56
being an untainted object with overloading that returns a tainted
a4ac56
stringification.  It looked at the taintedness of the object value, not
a4ac56
realising that taint could arise during the string concatenation per se.
a4ac56
Change the taint checks to look at the actual TAINT_get flag after string
a4ac56
concatenation.  This may falsely ascribe to the replacement taint that
a4ac56
actually came from somewhere else, but the end result is the same anyway:
a4ac56
there's no visible behaviour that distinguishes taint specifically from
a4ac56
the replacement.  Also remove a related taint check that seems to be
a4ac56
not needed at all.  Fixes [perl #115266].
a4ac56
a4ac56
Petr Písař: Ported to 5.26.1.
a4ac56
a4ac56
Signed-off-by: Petr Písař <ppisar@redhat.com>
a4ac56
---
a4ac56
 pp_ctl.c     |   4 +-
a4ac56
 pp_hot.c     |   4 +-
a4ac56
 t/op/taint.t | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
a4ac56
 3 files changed, 422 insertions(+), 14 deletions(-)
a4ac56
a4ac56
diff --git a/pp_ctl.c b/pp_ctl.c
a4ac56
index f136f91..15c193b 100644
a4ac56
--- a/pp_ctl.c
a4ac56
+++ b/pp_ctl.c
a4ac56
@@ -219,9 +219,9 @@ PP(pp_substcont)
a4ac56
 	SvGETMAGIC(TOPs); /* possibly clear taint on $1 etc: #67962 */
a4ac56
 
a4ac56
     	/* See "how taint works" above pp_subst() */
a4ac56
-	if (SvTAINTED(TOPs))
a4ac56
-	    cx->sb_rxtainted |= SUBST_TAINT_REPL;
a4ac56
 	sv_catsv_nomg(dstr, POPs);
a4ac56
+	if (UNLIKELY(TAINT_get))
a4ac56
+	    cx->sb_rxtainted |= SUBST_TAINT_REPL;
a4ac56
 	if (CxONCE(cx) || s < orig ||
a4ac56
                 !CALLREGEXEC(rx, s, cx->sb_strend, orig,
a4ac56
 			     (s == m), cx->sb_targ, NULL,
a4ac56
diff --git a/pp_hot.c b/pp_hot.c
a4ac56
index f445fd9..5899413 100644
a4ac56
--- a/pp_hot.c
a4ac56
+++ b/pp_hot.c
a4ac56
@@ -3250,7 +3250,7 @@ PP(pp_subst)
a4ac56
 	    doutf8 = DO_UTF8(dstr);
a4ac56
 	}
a4ac56
 
a4ac56
-	if (SvTAINTED(dstr))
a4ac56
+	if (UNLIKELY(TAINT_get))
a4ac56
 	    rxtainted |= SUBST_TAINT_REPL;
a4ac56
     }
a4ac56
     else {
a4ac56
@@ -3421,8 +3421,6 @@ PP(pp_subst)
a4ac56
 	    }
a4ac56
 	    else {
a4ac56
 		sv_catsv(dstr, repl);
a4ac56
-		if (UNLIKELY(SvTAINTED(repl)))
a4ac56
-		    rxtainted |= SUBST_TAINT_REPL;
a4ac56
 	    }
a4ac56
 	    if (once)
a4ac56
 		break;
a4ac56
diff --git a/t/op/taint.t b/t/op/taint.t
a4ac56
index c13eaf6..be5eaa8 100644
a4ac56
--- a/t/op/taint.t
a4ac56
+++ b/t/op/taint.t
a4ac56
@@ -17,7 +17,7 @@ BEGIN {
a4ac56
 use strict;
a4ac56
 use Config;
a4ac56
 
a4ac56
-plan tests => 828;
a4ac56
+plan tests => 1040;
a4ac56
 
a4ac56
 $| = 1;
a4ac56
 
a4ac56
@@ -83,6 +83,8 @@ EndOfCleanup
a4ac56
 # Sources of taint:
a4ac56
 #   The empty tainted value, for tainting strings
a4ac56
 my $TAINT = substr($^X, 0, 0);
a4ac56
+#   A tainted non-empty string
a4ac56
+my $TAINTXYZ = "xyz".$TAINT;
a4ac56
 #   A tainted zero, useful for tainting numbers
a4ac56
 my $TAINT0;
a4ac56
 {
a4ac56
@@ -565,7 +567,7 @@ my $TEST = 'TEST';
a4ac56
         is($one, 'abcd',   "$desc: \$1 value");
a4ac56
     }
a4ac56
 
a4ac56
-    $desc = "substitution with replacement tainted";
a4ac56
+    $desc = "substitution with partial replacement tainted";
a4ac56
 
a4ac56
     $s = 'abcd';
a4ac56
     $res = $s =~ s/(.+)/xyz$TAINT/;
a4ac56
@@ -577,7 +579,7 @@ my $TEST = 'TEST';
a4ac56
     is($res, 1,        "$desc: res value");
a4ac56
     is($one, 'abcd',   "$desc: \$1 value");
a4ac56
 
a4ac56
-    $desc = "substitution /g with replacement tainted";
a4ac56
+    $desc = "substitution /g with partial replacement tainted";
a4ac56
 
a4ac56
     $s = 'abcd';
a4ac56
     $res = $s =~ s/(.)/x$TAINT/g;
a4ac56
@@ -589,7 +591,7 @@ my $TEST = 'TEST';
a4ac56
     is($res, 4,        "$desc: res value");
a4ac56
     is($one, 'd',      "$desc: \$1 value");
a4ac56
 
a4ac56
-    $desc = "substitution /ge with replacement tainted";
a4ac56
+    $desc = "substitution /ge with partial replacement tainted";
a4ac56
 
a4ac56
     $s = 'abc';
a4ac56
     {
a4ac56
@@ -618,7 +620,7 @@ my $TEST = 'TEST';
a4ac56
     is($res, 3,        "$desc: res value");
a4ac56
     is($one, 'c',      "$desc: \$1 value");
a4ac56
 
a4ac56
-    $desc = "substitution /r with replacement tainted";
a4ac56
+    $desc = "substitution /r with partial replacement tainted";
a4ac56
 
a4ac56
     $s = 'abcd';
a4ac56
     $res = $s =~ s/(.+)/xyz$TAINT/r;
a4ac56
@@ -630,6 +632,71 @@ my $TEST = 'TEST';
a4ac56
     is($res, 'xyz',    "$desc: res value");
a4ac56
     is($one, 'abcd',   "$desc: \$1 value");
a4ac56
 
a4ac56
+    $desc = "substitution with whole replacement tainted";
a4ac56
+
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$TAINTXYZ/;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s,  'xyz',     "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /g with whole replacement tainted";
a4ac56
+
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/$TAINTXYZ/g;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s,  'xyz' x 4, "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /ge with whole replacement tainted";
a4ac56
+
a4ac56
+    $s = 'abc';
a4ac56
+    {
a4ac56
+	my $i = 0;
a4ac56
+	my $j;
a4ac56
+	$res = $s =~ s{(.)}{
a4ac56
+		    $j = $i; # make sure code not tainted
a4ac56
+		    $one = $1;
a4ac56
+		    isnt_tainted($j, "$desc: code not tainted within /e");
a4ac56
+		    $i++;
a4ac56
+		    if ($i == 1) {
a4ac56
+			isnt_tainted($s,   "$desc: s not tainted loop 1");
a4ac56
+		    }
a4ac56
+		    else {
a4ac56
+			is_tainted($s,     "$desc: s tainted loop $i");
a4ac56
+		    }
a4ac56
+		    isnt_tainted($one, "$desc: \$1 not tainted within /e");
a4ac56
+		    $TAINTXYZ;
a4ac56
+		}ge;
a4ac56
+	$one = $1;
a4ac56
+    }
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s,  'xyz' x 3, "$desc: s value");
a4ac56
+    is($res, 3,        "$desc: res value");
a4ac56
+    is($one, 'c',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /r with whole replacement tainted";
a4ac56
+
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$TAINTXYZ/r;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    is_tainted($res,   "$desc: res tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s,   'abcd',   "$desc: s value");
a4ac56
+    is($res, 'xyz',    "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
     {
a4ac56
 	# now do them all again with "use re 'taint"
a4ac56
 
a4ac56
@@ -955,7 +1022,7 @@ my $TEST = 'TEST';
a4ac56
         is($one, 'abcd',   "$desc: \$1 value");
a4ac56
     }
a4ac56
 
a4ac56
-	$desc = "use re 'taint': substitution with replacement tainted";
a4ac56
+	$desc = "use re 'taint': substitution with partial replacement tainted";
a4ac56
 
a4ac56
 	$s = 'abcd';
a4ac56
 	$res = $s =~ s/(.+)/xyz$TAINT/;
a4ac56
@@ -967,7 +1034,7 @@ my $TEST = 'TEST';
a4ac56
 	is($res, 1,        "$desc: res value");
a4ac56
 	is($one, 'abcd',   "$desc: \$1 value");
a4ac56
 
a4ac56
-	$desc = "use re 'taint': substitution /g with replacement tainted";
a4ac56
+	$desc = "use re 'taint': substitution /g with partial replacement tainted";
a4ac56
 
a4ac56
 	$s = 'abcd';
a4ac56
 	$res = $s =~ s/(.)/x$TAINT/g;
a4ac56
@@ -979,7 +1046,7 @@ my $TEST = 'TEST';
a4ac56
 	is($res, 4,        "$desc: res value");
a4ac56
 	is($one, 'd',      "$desc: \$1 value");
a4ac56
 
a4ac56
-	$desc = "use re 'taint': substitution /ge with replacement tainted";
a4ac56
+	$desc = "use re 'taint': substitution /ge with partial replacement tainted";
a4ac56
 
a4ac56
 	$s = 'abc';
a4ac56
 	{
a4ac56
@@ -1008,7 +1075,7 @@ my $TEST = 'TEST';
a4ac56
 	is($res, 3,        "$desc: res value");
a4ac56
 	is($one, 'c',      "$desc: \$1 value");
a4ac56
 
a4ac56
-	$desc = "use re 'taint': substitution /r with replacement tainted";
a4ac56
+	$desc = "use re 'taint': substitution /r with partial replacement tainted";
a4ac56
 
a4ac56
 	$s = 'abcd';
a4ac56
 	$res = $s =~ s/(.+)/xyz$TAINT/r;
a4ac56
@@ -1020,6 +1087,71 @@ my $TEST = 'TEST';
a4ac56
 	is($res, 'xyz',    "$desc: res value");
a4ac56
 	is($one, 'abcd',   "$desc: \$1 value");
a4ac56
 
a4ac56
+	$desc = "use re 'taint': substitution with whole replacement tainted";
a4ac56
+
a4ac56
+	$s = 'abcd';
a4ac56
+	$res = $s =~ s/(.+)/$TAINTXYZ/;
a4ac56
+	$one = $1;
a4ac56
+	is_tainted($s,     "$desc: s tainted");
a4ac56
+	isnt_tainted($res, "$desc: res not tainted");
a4ac56
+	isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+	is($s,  'xyz',     "$desc: s value");
a4ac56
+	is($res, 1,        "$desc: res value");
a4ac56
+	is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+	$desc = "use re 'taint': substitution /g with whole replacement tainted";
a4ac56
+
a4ac56
+	$s = 'abcd';
a4ac56
+	$res = $s =~ s/(.)/$TAINTXYZ/g;
a4ac56
+	$one = $1;
a4ac56
+	is_tainted($s,     "$desc: s tainted");
a4ac56
+	isnt_tainted($res, "$desc: res not tainted");
a4ac56
+	isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+	is($s,  'xyz' x 4, "$desc: s value");
a4ac56
+	is($res, 4,        "$desc: res value");
a4ac56
+	is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+	$desc = "use re 'taint': substitution /ge with whole replacement tainted";
a4ac56
+
a4ac56
+	$s = 'abc';
a4ac56
+	{
a4ac56
+	    my $i = 0;
a4ac56
+	    my $j;
a4ac56
+	    $res = $s =~ s{(.)}{
a4ac56
+			$j = $i; # make sure code not tainted
a4ac56
+			$one = $1;
a4ac56
+			isnt_tainted($j, "$desc: code not tainted within /e");
a4ac56
+			$i++;
a4ac56
+			if ($i == 1) {
a4ac56
+			    isnt_tainted($s,   "$desc: s not tainted loop 1");
a4ac56
+			}
a4ac56
+			else {
a4ac56
+			    is_tainted($s,     "$desc: s tainted loop $i");
a4ac56
+			}
a4ac56
+			    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+			$TAINTXYZ;
a4ac56
+		    }ge;
a4ac56
+	    $one = $1;
a4ac56
+	}
a4ac56
+	is_tainted($s,     "$desc: s tainted");
a4ac56
+	isnt_tainted($res, "$desc: res tainted");
a4ac56
+	isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+	is($s,  'xyz' x 3, "$desc: s value");
a4ac56
+	is($res, 3,        "$desc: res value");
a4ac56
+	is($one, 'c',      "$desc: \$1 value");
a4ac56
+
a4ac56
+	$desc = "use re 'taint': substitution /r with whole replacement tainted";
a4ac56
+
a4ac56
+	$s = 'abcd';
a4ac56
+	$res = $s =~ s/(.+)/$TAINTXYZ/r;
a4ac56
+	$one = $1;
a4ac56
+	isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+	is_tainted($res,   "$desc: res tainted");
a4ac56
+	isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+	is($s,   'abcd',   "$desc: s value");
a4ac56
+	is($res, 'xyz',    "$desc: res value");
a4ac56
+	is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
         # [perl #121854] match taintedness became sticky
a4ac56
         # when one match has a taintess result, subseqent matches
a4ac56
         # using the same pattern shouldn't necessarily be tainted
a4ac56
@@ -2448,6 +2580,284 @@ is eval { eval $::x.1 }, 1, 'reset does not taint undef';
a4ac56
     isnt_tainted $b, "list assign post tainted expression b";
a4ac56
 }
a4ac56
 
a4ac56
+# taint passing through overloading
a4ac56
+package OvTaint {
a4ac56
+    sub new { bless({ t => $_[1] }, $_[0]) }
a4ac56
+    use overload '""' => sub { $_[0]->{t} ? "hi".$TAINT : "hello" };
a4ac56
+}
a4ac56
+my $ovclean = OvTaint->new(0);
a4ac56
+my $ovtaint = OvTaint->new(1);
a4ac56
+isnt_tainted("$ovclean", "overload preserves cleanliness");
a4ac56
+is_tainted("$ovtaint", "overload preserves taint");
a4ac56
+
a4ac56
+# substitutions with overloaded replacement
a4ac56
+{
a4ac56
+    my ($desc, $s, $res, $one);
a4ac56
+
a4ac56
+    $desc = "substitution with partial replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/xyz$ovclean/;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xyzhello', "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution with partial replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/xyz$ovtaint/;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xyzhi',    "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution with whole replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$ovclean/;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hello',    "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution with whole replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$ovtaint/;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hi',       "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with partial replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/"xyz".$ovclean/e;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xyzhello', "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with partial replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/"xyz".$ovtaint/e;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xyzhi',    "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with whole replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$ovclean/e;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hello',    "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with whole replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$ovtaint/e;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hi',       "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with extra code and partial replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/(my $z++), "xyz".$ovclean/e;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xyzhello', "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with extra code and partial replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/(my $z++), "xyz".$ovtaint/e;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xyzhi',    "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with extra code and whole replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/(my $z++), $ovclean/e;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hello',    "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /e with extra code and whole replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/(my $z++), $ovtaint/e;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hi',       "$desc: s value");
a4ac56
+    is($res, 1,        "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /r with partial replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/xyz$ovclean/r;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'abcd',     "$desc: s value");
a4ac56
+    is($res, 'xyzhello', "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /r with partial replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/xyz$ovtaint/r;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    is_tainted($res,   "$desc: res tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'abcd',     "$desc: s value");
a4ac56
+    is($res, 'xyzhi',  "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /r with whole replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$ovclean/r;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'abcd',     "$desc: s value");
a4ac56
+    is($res, 'hello',  "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /r with whole replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.+)/$ovtaint/r;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    is_tainted($res,   "$desc: res tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'abcd',     "$desc: s value");
a4ac56
+    is($res, 'hi',     "$desc: res value");
a4ac56
+    is($one, 'abcd',   "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /g with partial replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/x$ovclean/g;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xhello' x 4, "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /g with partial replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/x$ovtaint/g;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xhi' x 4,  "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /g with whole replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/$ovclean/g;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hello' x 4, "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /g with whole replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/$ovtaint/g;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hi' x 4,   "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /ge with partial replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/"x".$ovclean/ge;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xhello' x 4, "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /ge with partial replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/"x".$ovtaint/ge;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'xhi' x 4,  "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /ge with whole replacement overloaded and clean";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/$ovclean/ge;
a4ac56
+    $one = $1;
a4ac56
+    isnt_tainted($s,   "$desc: s not tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hello' x 4, "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+
a4ac56
+    $desc = "substitution /ge with whole replacement overloaded and tainted";
a4ac56
+    $s = 'abcd';
a4ac56
+    $res = $s =~ s/(.)/$ovtaint/ge;
a4ac56
+    $one = $1;
a4ac56
+    is_tainted($s,     "$desc: s tainted");
a4ac56
+    isnt_tainted($res, "$desc: res not tainted");
a4ac56
+    isnt_tainted($one, "$desc: \$1 not tainted");
a4ac56
+    is($s, 'hi' x 4,   "$desc: s value");
a4ac56
+    is($res, 4,        "$desc: res value");
a4ac56
+    is($one, 'd',      "$desc: \$1 value");
a4ac56
+}
a4ac56
 
a4ac56
 # This may bomb out with the alarm signal so keep it last
a4ac56
 SKIP: {
a4ac56
-- 
a4ac56
2.13.6
a4ac56