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