Open p5pRT opened 9 years ago
This is a bug report for perl from mark@markandruth.co.uk\, generated with the help of perlbug 1.39 running under perl 5.18.2.
-----------------------------------------------------------------
A simple script like:
use threads; use Devel::Peek; use threads::shared; my $var = { a => 0.1 + 0 }; Dump($var); my $t = shared_clone $var; Dump( $t->{a} ); my $v = $t->{a}; my %v = %$t; Dump($v); Dump($v{a});
Produces somewhat incorrect output on the first Dump statement compared to the second two (see below). This shows that dereferencing a shared_clone hash value directly does not produce the same information as copying it to a variable in the local thread. I found this issue using MongoDB as we wanted to store a double datatype\, however when dereferencing straight from a shared variable it was inserting a string.
A solution is to clone (using pure-perl) into the local thread using a function like:
sub _fix_dequeue { my ( $v ) = @_;
my $ref = ref $v or return $v;
my $ret; if ( $ref eq 'ARRAY' ) { $ret = [ map { _fix_dequeue( $_ ) } @$v ]; } elsif ( $ref eq 'HASH' ) { $ret = { map { $_ => _fix_dequeue( $v->{$_} ) } keys %$v }; }
return $ret; }
Here is the output of the first program on my computer showing the dereference compared to copying to local thread produces different results for a SvNV type.
SV = IV(0x1311bb0) at 0x1311bc0 REFCNT = 1 FLAGS = (PADMY\,ROK) RV = 0x12e9cb8 SV = PVHV(0x12f09b0) at 0x12e9cb8 REFCNT = 1 FLAGS = (SHAREKEYS) ARRAY = 0x131a920 (0:7\, 1:1) hash quality = 100.0% KEYS = 1 FILL = 1 MAX = 7 Elt "a" HASH = 0x1bb2e90c SV = NV(0x13283e8) at 0x12e9e98 REFCNT = 1 FLAGS = (NOK\,pNOK) NV = 0.1 SV = PVLV(0xaf5010) at 0xa82e98 REFCNT = 1 FLAGS = (TEMP\,GMG\,SMG\,RMG) IV = 0 NV = 0 PV = 0 MAGIC = 0xaa3df0 MG_VIRTUAL = 0x7fb7749412e0 MG_TYPE = PERL_MAGIC_tiedelem(p) MG_FLAGS = 0x12 REFCOUNTED DUP MG_OBJ = 0xaa08e0 SV = IV(0xaa08d0) at 0xaa08e0 REFCNT = 2 FLAGS = (ROK) RV = 0xaa0958 SV = PVMG(0xb69ed0) at 0xaa0958 REFCNT = 1 FLAGS = (OBJECT\,IOK\,pIOK) IV = 12141928 NV = 0 PV = 0 STASH = 0xb73130 "threads::shared::tie" MG_LEN = -2 MG_PTR = 0xa82cb8 => HEf_SVKEY SV = PV(0xa83ba0) at 0xa82cb8 REFCNT = 2 FLAGS = (POK\,pPOK) PV = 0xa882e0 "a"\0 CUR = 1 LEN = 16 TYPE = T TARGOFF = 0 TARGLEN = 0 TARG = 0xafd5d0 FLAGS = 0 SV = PVNV(0xb3fe00) at 0xb8b9a0 REFCNT = 1 FLAGS = (PADMY\,NOK\,pNOK) IV = 0 NV = 0.1 PV = 0 SV = PVMG(0xb69f30) at 0xba5f00 REFCNT = 1 FLAGS = (NOK\,pNOK) IV = 0 NV = 0.1 PV = 0
Le 10/08/2015 06:47\, Mark Zealey (via RT) a écrit :
A simple script like:
use threads; use Devel::Peek; use threads::shared; my $var = { a => 0.1 + 0 }; Dump($var); my $t = shared_clone $var; Dump( $t->{a} ); my $v = $t->{a}; my %v = %$t; Dump($v); Dump($v{a});
Produces somewhat incorrect output on the first Dump statement compared to the second two (see below). This shows that dereferencing a shared_clone hash value directly does not produce the same information as copying it to a variable in the local thread. I found this issue using MongoDB as we wanted to store a double datatype\, however when dereferencing straight from a shared variable it was inserting a string.
This is not a bug but the normal behaviour of tied hashes\, which are used to implement shared hashes : fetching values from a tied hash returns a temporary proxy SV that will live until the actual action (assignment from or to the hash element) is known by perl. The MongoDB XS module is probably missing a SvGETMAGIC() somewhere to force the 'get' magic call to be resolved\, which will yield the correct value (this is also what happens when the pure perl assignment takes place). Devel::Peek::Dump shows the intermediate value because it does not call 'get' magic by design\, so that it is possible to debug magical SVs.
Vincent
The RT System itself - Status changed from 'new' to 'open'
On Mon Aug 10 09:43:10 2015\, perl@profvince.com wrote:
Le 10/08/2015 06:47\, Mark Zealey (via RT) a écrit :
A simple script like:
use threads; use Devel::Peek; use threads::shared; my $var = { a => 0.1 + 0 }; Dump($var); my $t = shared_clone $var; Dump( $t->{a} ); my $v = $t->{a}; my %v = %$t; Dump($v); Dump($v{a});
Produces somewhat incorrect output on the first Dump statement compared to the second two (see below). This shows that dereferencing a shared_clone hash value directly does not produce the same information as copying it to a variable in the local thread. I found this issue using MongoDB as we wanted to store a double datatype\, however when dereferencing straight from a shared variable it was inserting a string.
This is not a bug but the normal behaviour of tied hashes\, which are used to implement shared hashes : fetching values from a tied hash returns a temporary proxy SV that will live until the actual action (assignment from or to the hash element) is known by perl. The MongoDB XS module is probably missing a SvGETMAGIC() somewhere to force the 'get' magic call to be resolved\, which will yield the correct value (this is also what happens when the pure perl assignment takes place). Devel::Peek::Dump shows the intermediate value because it does not call 'get' magic by design\, so that it is possible to debug magical SVs.
This code at https://github.com/mongodb/mongo-perl-driver/blob/master/perl_mongo.c#L642 looks incorrect to me:
if (!SvOK(sv)) { if (SvGMAGICAL(sv)) { mg_get(sv); } }
Tony
On Mon\, Aug 10\, 2015 at 7:37 PM\, Tony Cook via RT \<perlbug-followup@perl.org
wrote:
This code at https://github.com/mongodb/mongo-perl-driver/blob/master/perl_mongo.c#L642 looks incorrect to me:
if (!SvOK(sv)) { if (SvGMAGICAL(sv)) { mg_get(sv); } }
I'd welcome any suggestions. The inner "if" is just (an inefficient) SvGETMAGIC. I'm not sure why the original logic deferred resolving get magic if SvOK is true.
I can replicate the OP's problem on Perl's before 5.18. Looking at changes between 5.16 and 5.18\, I suspect it was "fixed" with commit 4bac9ae4 which stopped changing public flags to private flags in mg_get.
Doing the inverse on older Perls -- promoting private flags to public if there are not any existing public flags -- appears to solve the problem.
David
-- David Golden \xdg@​xdg\.me Twitter/IRC: @xdg
On Mon\, Aug 10\, 2015 at 09:52:47PM -0400\, David Golden wrote:
On Mon\, Aug 10\, 2015 at 7:37 PM\, Tony Cook via RT \<perlbug-followup@perl.org
wrote:
This code at https://github.com/mongodb/mongo-perl-driver/blob/master/perl_mongo.c#L642 looks incorrect to me:
if (!SvOK(sv)) { if (SvGMAGICAL(sv)) { mg_get(sv); } }
I'd welcome any suggestions. The inner "if" is just (an inefficient) SvGETMAGIC. I'm not sure why the original logic deferred resolving get magic if SvOK is true.
You don't need or want the if (!SvOK(sv)) test.
The:
if (SvGMAGICAL(sv)) { mg_get(sv); }
is essentially just SvGETMAGIC():
#define SvGETMAGIC(x) ((void)(UNLIKELY(SvGMAGICAL(x)) && mg_get(x)))
I can replicate the OP's problem on Perl's before 5.18. Looking at changes between 5.16 and 5.18\, I suspect it was "fixed" with commit 4bac9ae4 which stopped changing public flags to private flags in mg_get.
Doing the inverse on older Perls -- promoting private flags to public if there are not any existing public flags -- appears to solve the problem.
Code that wants to deal with older perls should probably check the private flags\, at least for magical values.
Tony
Migrated from rt.perl.org#125778 (status was 'open')
Searchable as RT125778$