Skip to content

Commit

Permalink
don't clobber file bytes in :encoding layer
Browse files Browse the repository at this point in the history
The PerlIO::encoding layer, when used on input, was creating an SvLEN==0
scalar pointing into the byte buffer, to pass to the ->decode method
of the encoding object.  Since the method mutates this scalar, for some
encodings this led to mutating the byte buffer, and depending on where
it came from that might be something visible elsewhere that should not
be mutated.  Remove the code for the SvLEN==0 scalar, instead always
using the alternate code that would copy the bytes into a separate buffer
owned by the scalar.  Fixes [perl #132833].
  • Loading branch information
Zefram committed Feb 16, 2018
1 parent 4bd1355 commit fed9fe5
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 35 deletions.
2 changes: 1 addition & 1 deletion ext/PerlIO-encoding/encoding.pm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package PerlIO::encoding;

use strict;
our $VERSION = '0.25';
our $VERSION = '0.26';
our $DEBUG = 0;
$DEBUG and warn __PACKAGE__, " called by ", join(", ", caller), "\n";

Expand Down
43 changes: 10 additions & 33 deletions ext/PerlIO-encoding/encoding.xs
Original file line number Diff line number Diff line change
Expand Up @@ -307,42 +307,19 @@ PerlIOEncode_fill(pTHX_ PerlIO * f)
goto end_of_file;
}
}
if (SvCUR(e->dataSV)) {
/* something left over from last time - create a normal
SV with new data appended
*/
if (use + SvCUR(e->dataSV) > e->base.bufsiz) {
if (e->flags & NEEDS_LINES) {
/* Have to grow buffer */
e->base.bufsiz = use + SvCUR(e->dataSV);
PerlIOEncode_get_base(aTHX_ f);
}
else {
use = e->base.bufsiz - SvCUR(e->dataSV);
}
}
sv_catpvn(e->dataSV,(char*)ptr,use);
}
else {
/* Create a "dummy" SV to represent the available data from layer below */
if (SvLEN(e->dataSV) && SvPVX_const(e->dataSV)) {
Safefree(SvPVX_mutable(e->dataSV));
}
if (use > (SSize_t)e->base.bufsiz) {
if (e->flags & NEEDS_LINES) {
/* Have to grow buffer */
e->base.bufsiz = use;
PerlIOEncode_get_base(aTHX_ f);
}
else {
use = e->base.bufsiz;
if (!SvCUR(e->dataSV))
SvPVCLEAR(e->dataSV);
if (use + SvCUR(e->dataSV) > e->base.bufsiz) {
if (e->flags & NEEDS_LINES) {
/* Have to grow buffer */
e->base.bufsiz = use + SvCUR(e->dataSV);
PerlIOEncode_get_base(aTHX_ f);
}
else {
use = e->base.bufsiz - SvCUR(e->dataSV);
}
SvPV_set(e->dataSV, (char *) ptr);
SvLEN_set(e->dataSV, 0); /* Hands off sv.c - it isn't yours */
SvCUR_set(e->dataSV,use);
SvPOK_only(e->dataSV);
}
sv_catpvn(e->dataSV,(char*)ptr,use);
SvUTF8_off(e->dataSV);
PUSHMARK(sp);
XPUSHs(e->enc);
Expand Down
12 changes: 11 additions & 1 deletion ext/PerlIO-encoding/t/encoding.t
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ BEGIN {
require "../../t/charset_tools.pl";
}

use Test::More tests => 24;
use Test::More tests => 27;

my $grk = "grk$$";
my $utf = "utf$$";
Expand Down Expand Up @@ -231,6 +231,16 @@ is $x, "To hymn him who heard her herd herd\n",

} # SKIP

# decoding shouldn't mutate the original bytes [perl #132833]
{
my $b = "a\0b\0\n\0";
open my $fh, "<:encoding(UTF16-LE)", \$b or die;
is scalar(<$fh>), "ab\n";
is $b, "a\0b\0\n\0";
close $fh or die;
is $b, "a\0b\0\n\0";
}

END {
1 while unlink($grk, $utf, $fail1, $fail2, $russki, $threebyte);
}

0 comments on commit fed9fe5

Please sign in to comment.