734417
From a1e8f04634112d64383f0079421cf9cf5a154c0e Mon Sep 17 00:00:00 2001
734417
From: Vincent Pit <perl@profvince.com>
734417
Date: Fri, 28 Aug 2015 14:17:00 -0300
734417
Subject: [PATCH] Properly duplicate PerlIO::encoding objects
734417
MIME-Version: 1.0
734417
Content-Type: text/plain; charset=UTF-8
734417
Content-Transfer-Encoding: 8bit
734417
734417
Upstream commit ported to 5.16.3:
734417
734417
commit 0ee3fa26f660ac426e3e082f77d806c9d1471f93
734417
Author: Vincent Pit <perl@profvince.com>
734417
Date:   Fri Aug 28 14:17:00 2015 -0300
734417
734417
    Properly duplicate PerlIO::encoding objects
734417
734417
    PerlIO::encoding objects are usually initialized by calling Perl methods,
734417
    essentially from the pushed() and getarg() callbacks. During cloning, the
734417
    PerlIO API will by default call these methods to initialize the duplicate
734417
    struct when the PerlIOBase parent struct is itself duplicated. This does
734417
    not behave so well because the perl interpreter is not ready to call
734417
    methods at this point, for the stacks are not set up yet.
734417
734417
    The proper way to duplicate the PerlIO::encoding object is to call sv_dup()
734417
    on its members from the dup() PerlIO callback. So the only catch is to make
734417
    the getarg() and pushed() calls implied by the duplication of the underlying
734417
    PerlIOBase object aware that they are called during cloning, and make them
734417
    wait that the control flow returns to the dup() callback. Fortunately,
734417
    getarg() knows since its param argument is then non-null, and its return
734417
    value is passed immediately to pushed(), so it is enough to tag this
734417
    returned value with a custom magic so that pushed() can see it is being
734417
    called during cloning.
734417
734417
    This fixes [RT #31923].
734417
734417
Signed-off-by: Petr Písař <ppisar@redhat.com>
734417
---
734417
 MANIFEST                        |  1 +
734417
 ext/PerlIO-encoding/encoding.xs | 25 +++++++++++++++++++++++--
734417
 ext/PerlIO-encoding/t/threads.t | 35 +++++++++++++++++++++++++++++++++++
734417
 3 files changed, 59 insertions(+), 2 deletions(-)
734417
 create mode 100644 ext/PerlIO-encoding/t/threads.t
734417
734417
diff --git a/MANIFEST b/MANIFEST
734417
index 02e8234..5caa981 100644
734417
--- a/MANIFEST
734417
+++ b/MANIFEST
734417
@@ -3791,6 +3791,7 @@ ext/PerlIO-encoding/MANIFEST	PerlIO::encoding list of files
734417
 ext/PerlIO-encoding/t/encoding.t	See if PerlIO encoding conversion works
734417
 ext/PerlIO-encoding/t/fallback.t	See if PerlIO fallbacks work
734417
 ext/PerlIO-encoding/t/nolooping.t	Tests for PerlIO::encoding
734417
+ext/PerlIO-encoding/t/threads.t		Tests PerlIO::encoding and threads
734417
 ext/PerlIO-mmap/mmap.pm	PerlIO layer for memory maps
734417
 ext/PerlIO-mmap/mmap.xs	PerlIO layer for memory maps
734417
 ext/PerlIO-scalar/scalar.pm	PerlIO layer for scalars
734417
diff --git a/ext/PerlIO-encoding/encoding.xs b/ext/PerlIO-encoding/encoding.xs
734417
index 98d89e9..d5efb62 100644
734417
--- a/ext/PerlIO-encoding/encoding.xs
734417
+++ b/ext/PerlIO-encoding/encoding.xs
734417
@@ -49,13 +49,23 @@ typedef struct {
734417
 
734417
 #define NEEDS_LINES	1
734417
 
734417
+static const MGVTBL PerlIOEncode_tag = { 0, 0, 0, 0, 0, 0, 0, 0 };
734417
+
734417
 SV *
734417
 PerlIOEncode_getarg(pTHX_ PerlIO * f, CLONE_PARAMS * param, int flags)
734417
 {
734417
     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
734417
-    SV *sv = &PL_sv_undef;
734417
-    PERL_UNUSED_ARG(param);
734417
+    SV *sv;
734417
     PERL_UNUSED_ARG(flags);
734417
+    /* During cloning, return an undef token object so that _pushed() knows
734417
+     * that it should not call methods and wait for _dup() to actually dup the
734417
+     * encoding object. */
734417
+    if (param) {
734417
+	sv = newSV(0);
734417
+	sv_magicext(sv, NULL, PERL_MAGIC_ext, &PerlIOEncode_tag, 0, 0);
734417
+	return sv;
734417
+    }
734417
+    sv = &PL_sv_undef;
734417
     if (e->enc) {
734417
 	dSP;
734417
 	/* Not 100% sure stack swap is right thing to do during dup ... */
734417
@@ -86,6 +96,14 @@ PerlIOEncode_pushed(pTHX_ PerlIO * f, const char *mode, SV * arg, PerlIO_funcs *
734417
     IV  code = PerlIOBuf_pushed(aTHX_ f, mode, Nullsv,tab);
734417
     SV *result = Nullsv;
734417
 
734417
+    if (SvTYPE(arg) >= SVt_PVMG
734417
+		&& mg_findext(arg, PERL_MAGIC_ext, &PerlIOEncode_tag)) {
734417
+	e->enc = NULL;
734417
+	e->chk = NULL;
734417
+	e->inEncodeCall = 0;
734417
+	return code;
734417
+    }
734417
+
734417
     PUSHSTACKi(PERLSI_MAGIC);
734417
     SPAGAIN;
734417
 
734417
@@ -558,6 +576,9 @@ PerlIOEncode_dup(pTHX_ PerlIO * f, PerlIO * o,
734417
 	if (oe->enc) {
734417
 	    fe->enc = PerlIO_sv_dup(aTHX_ oe->enc, params);
734417
 	}
734417
+	if (oe->chk) {
734417
+	    fe->chk = PerlIO_sv_dup(aTHX_ oe->chk, params);
734417
+	}
734417
     }
734417
     return f;
734417
 }
734417
diff --git a/ext/PerlIO-encoding/t/threads.t b/ext/PerlIO-encoding/t/threads.t
734417
new file mode 100644
734417
index 0000000..64f0e55
734417
--- /dev/null
734417
+++ b/ext/PerlIO-encoding/t/threads.t
734417
@@ -0,0 +1,35 @@
734417
+#!perl
734417
+
734417
+use strict;
734417
+use warnings;
734417
+
734417
+BEGIN {
734417
+    use Config;
734417
+    if ($Config{extensions} !~ /\bEncode\b/) {
734417
+	print "1..0 # Skip: no Encode\n";
734417
+	exit 0;
734417
+    }
734417
+    unless ($Config{useithreads}) {
734417
+	print "1..0 # Skip: no threads\n";
734417
+	exit 0;
734417
+    }
734417
+}
734417
+
734417
+use threads;
734417
+
734417
+use Test::More tests => 3 + 1;
734417
+
734417
+binmode *STDOUT, ':encoding(UTF-8)';
734417
+
734417
+SKIP: {
734417
+    local $@;
734417
+    my $ret = eval {
734417
+	my $thread = threads->create(sub { pass 'in thread'; return 1 });
734417
+	skip 'test thread could not be spawned' => 3 unless $thread;
734417
+	$thread->join;
734417
+    };
734417
+    is $@, '', 'thread did not croak';
734417
+    is $ret, 1, 'thread returned the right value';
734417
+}
734417
+
734417
+pass 'passes at least one test';
734417
-- 
734417
2.5.5
734417