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