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