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