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