b8c914
From fed9fe5b48ccdffef9065a03c12c237cc7418de6 Mon Sep 17 00:00:00 2001
b8c914
From: Zefram <zefram@fysh.org>
b8c914
Date: Fri, 16 Feb 2018 17:20:34 +0000
b8c914
Subject: [PATCH] don't clobber file bytes in :encoding layer
b8c914
MIME-Version: 1.0
b8c914
Content-Type: text/plain; charset=UTF-8
b8c914
Content-Transfer-Encoding: 8bit
b8c914
b8c914
The PerlIO::encoding layer, when used on input, was creating an SvLEN==0
b8c914
scalar pointing into the byte buffer, to pass to the ->decode method
b8c914
of the encoding object.  Since the method mutates this scalar, for some
b8c914
encodings this led to mutating the byte buffer, and depending on where
b8c914
it came from that might be something visible elsewhere that should not
b8c914
be mutated.  Remove the code for the SvLEN==0 scalar, instead always
b8c914
using the alternate code that would copy the bytes into a separate buffer
b8c914
owned by the scalar.  Fixes [perl #132833].
b8c914
b8c914
Signed-off-by: Petr Písař <ppisar@redhat.com>
b8c914
---
b8c914
 ext/PerlIO-encoding/encoding.pm  |  2 +-
b8c914
 ext/PerlIO-encoding/encoding.xs  | 43 ++++++++++------------------------------
b8c914
 ext/PerlIO-encoding/t/encoding.t | 12 ++++++++++-
b8c914
 3 files changed, 22 insertions(+), 35 deletions(-)
b8c914
b8c914
diff --git a/ext/PerlIO-encoding/encoding.pm b/ext/PerlIO-encoding/encoding.pm
b8c914
index 08d2df4713..3d740b181a 100644
b8c914
--- a/ext/PerlIO-encoding/encoding.pm
b8c914
+++ b/ext/PerlIO-encoding/encoding.pm
b8c914
@@ -1,7 +1,7 @@
b8c914
 package PerlIO::encoding;
b8c914
 
b8c914
 use strict;
b8c914
-our $VERSION = '0.25';
b8c914
+our $VERSION = '0.26';
b8c914
 our $DEBUG = 0;
b8c914
 $DEBUG and warn __PACKAGE__, " called by ", join(", ", caller), "\n";
b8c914
 
b8c914
diff --git a/ext/PerlIO-encoding/encoding.xs b/ext/PerlIO-encoding/encoding.xs
b8c914
index bb4754f3d9..941d786266 100644
b8c914
--- a/ext/PerlIO-encoding/encoding.xs
b8c914
+++ b/ext/PerlIO-encoding/encoding.xs
b8c914
@@ -307,42 +307,19 @@ PerlIOEncode_fill(pTHX_ PerlIO * f)
b8c914
 		goto end_of_file;
b8c914
 	    }
b8c914
 	}
b8c914
-	if (SvCUR(e->dataSV)) {
b8c914
-	    /* something left over from last time - create a normal
b8c914
-	       SV with new data appended
b8c914
-	     */
b8c914
-	    if (use + SvCUR(e->dataSV) > e->base.bufsiz) {
b8c914
-		if (e->flags & NEEDS_LINES) {
b8c914
-		    /* Have to grow buffer */
b8c914
-		    e->base.bufsiz = use + SvCUR(e->dataSV);
b8c914
-		    PerlIOEncode_get_base(aTHX_ f);
b8c914
-		}
b8c914
-		else {
b8c914
-	       use = e->base.bufsiz - SvCUR(e->dataSV);
b8c914
-	    }
b8c914
-	    }
b8c914
-	    sv_catpvn(e->dataSV,(char*)ptr,use);
b8c914
-	}
b8c914
-	else {
b8c914
-	    /* Create a "dummy" SV to represent the available data from layer below */
b8c914
-	    if (SvLEN(e->dataSV) && SvPVX_const(e->dataSV)) {
b8c914
-		Safefree(SvPVX_mutable(e->dataSV));
b8c914
-	    }
b8c914
-	    if (use > (SSize_t)e->base.bufsiz) {
b8c914
-		if (e->flags & NEEDS_LINES) {
b8c914
-		    /* Have to grow buffer */
b8c914
-		    e->base.bufsiz = use;
b8c914
-		    PerlIOEncode_get_base(aTHX_ f);
b8c914
-		}
b8c914
-		else {
b8c914
-	       use = e->base.bufsiz;
b8c914
+	if (!SvCUR(e->dataSV))
b8c914
+	    SvPVCLEAR(e->dataSV);
b8c914
+	if (use + SvCUR(e->dataSV) > e->base.bufsiz) {
b8c914
+	    if (e->flags & NEEDS_LINES) {
b8c914
+		/* Have to grow buffer */
b8c914
+		e->base.bufsiz = use + SvCUR(e->dataSV);
b8c914
+		PerlIOEncode_get_base(aTHX_ f);
b8c914
 	    }
b8c914
+	    else {
b8c914
+		use = e->base.bufsiz - SvCUR(e->dataSV);
b8c914
 	    }
b8c914
-	    SvPV_set(e->dataSV, (char *) ptr);
b8c914
-	    SvLEN_set(e->dataSV, 0);  /* Hands off sv.c - it isn't yours */
b8c914
-	    SvCUR_set(e->dataSV,use);
b8c914
-	    SvPOK_only(e->dataSV);
b8c914
 	}
b8c914
+	sv_catpvn(e->dataSV,(char*)ptr,use);
b8c914
 	SvUTF8_off(e->dataSV);
b8c914
 	PUSHMARK(sp);
b8c914
 	XPUSHs(e->enc);
b8c914
diff --git a/ext/PerlIO-encoding/t/encoding.t b/ext/PerlIO-encoding/t/encoding.t
b8c914
index 088f89ee20..41cefcb137 100644
b8c914
--- a/ext/PerlIO-encoding/t/encoding.t
b8c914
+++ b/ext/PerlIO-encoding/t/encoding.t
b8c914
@@ -16,7 +16,7 @@ BEGIN {
b8c914
     require "../../t/charset_tools.pl";
b8c914
 }
b8c914
 
b8c914
-use Test::More tests => 24;
b8c914
+use Test::More tests => 27;
b8c914
 
b8c914
 my $grk = "grk$$";
b8c914
 my $utf = "utf$$";
b8c914
@@ -231,6 +231,16 @@ is $x, "To hymn him who heard her herd herd\n",
b8c914
 
b8c914
 } # SKIP
b8c914
 
b8c914
+# decoding shouldn't mutate the original bytes [perl #132833]
b8c914
+{
b8c914
+    my $b = "a\0b\0\n\0";
b8c914
+    open my $fh, "<:encoding(UTF16-LE)", \$b or die;
b8c914
+    is scalar(<$fh>), "ab\n";
b8c914
+    is $b, "a\0b\0\n\0";
b8c914
+    close $fh or die;
b8c914
+    is $b, "a\0b\0\n\0";
b8c914
+}
b8c914
+
b8c914
 END {
b8c914
     1 while unlink($grk, $utf, $fail1, $fail2, $russki, $threebyte);
b8c914
 }
b8c914
-- 
b8c914
2.14.3
b8c914