On Mon, Mar 21, 2005 at 08:42:11PM -0000, philippe. cote @ usherbrooke.
ca wrote:
sv_rvweaken doesn't handle tied variables
Proof :
+-------------------------------------------------------------------------+
Sample code
+-------------------------------------------------------------------------+
#!/usr/bin/perl
use strict;
use warnings;
use Util::Monitor;
use Scalar::Util qw(weaken);
use Devel::Peek;
{
my (@a);
$a[0] = [EMAIL PROTECTED];
#tie @a, 'TestArray';
Dump($a[0],1);
weaken($a[0]);
Dump($a[0],1);
print "Leaving scope\n";
}
print "Scope left\n";
package TestArray;
use Tie::Array;
use base 'Tie::StdArray';
sub DESTROY { print "Monitor::TestArray::DESTROY : $_[0]\n"; }
1;
+-------------------------------------------------------------------------+
Output without "tie @a, 'TestArray'"
(Just to show you that weaken works without the tie)
+-------------------------------------------------------------------------+
SV = RV(0x81829c0) at 0x814127c
REFCNT = 1
FLAGS = (ROK)
RV = 0x814e740
SV = PVAV(0x81426cc) at 0x814e740
REFCNT = 2
FLAGS = (PADBUSY,PADMY)
IV = 0
NV = 0
ARRAY = 0x8148888
FILL = 0
MAX = 3
ARYLEN = 0x0
FLAGS = (REAL)
SV = RV(0x81829c0) at 0x814127c
REFCNT = 1
FLAGS = (ROK,WEAKREF,IsUV)
RV = 0x814e740
SV = PVAV(0x81426cc) at 0x814e740
REFCNT = 1
FLAGS = (PADBUSY,PADMY,RMG)
IV = 0
NV = 0
MAGIC = 0x8266f08
MG_VIRTUAL = &PL_vtbl_backref
MG_TYPE = PERL_MAGIC_backref(<)
MG_FLAGS = 0x02
REFCOUNTED
MG_OBJ = 0x81411c8
SV = PVAV(0x8263704) at 0x81411c8
REFCNT = 2
FLAGS = ()
IV = 0
NV = 0
ARRAY = 0x82677e8
FILL = 0
MAX = 3
ARYLEN = 0x0
FLAGS = (REAL)
ARRAY = 0x8148888
FILL = 0
MAX = 3
ARYLEN = 0x0
FLAGS = (REAL)
Leaving scope
Scope left
+-------------------------------------------------------------------------+
Output with "tie @a, 'TestArray';"
+-------------------------------------------------------------------------+
SV = PVLV(0x817c568) at 0x81413f0
REFCNT = 1
FLAGS = (TEMP,GMG,SMG,RMG)
IV = 0
NV = 0
PV = 0
MAGIC = 0x81505b8
MG_VIRTUAL = &PL_vtbl_packelem
MG_TYPE = PERL_MAGIC_tiedelem(p)
MG_FLAGS = 0x02
REFCOUNTED
MG_OBJ = 0x814139c
SV = RV(0x81829ac) at 0x814139c
REFCNT = 2
FLAGS = (ROK)
RV = 0x8141354
TYPE = t
TARGOFF = 0
TARGLEN = 0
TARG = 0x81413f0
SV = PVLV(0x817c568) at 0x81413f0
REFCNT = 1
FLAGS = (TEMP,GMG,SMG,RMG)
IV = 0
NV = 0
PV = 0
MAGIC = 0x81505b8
MG_VIRTUAL = &PL_vtbl_packelem
MG_TYPE = PERL_MAGIC_tiedelem(p)
MG_FLAGS = 0x02
REFCOUNTED
MG_OBJ = 0x814139c
SV = RV(0x81829ac) at 0x814139c
REFCNT = 2
FLAGS = (ROK)
RV = 0x8141354
TYPE = t
TARGOFF = 0
TARGLEN = 0
TARG = 0x81413f0
Leaving scope
Scope left
Monitor::TestArray::DESTROY : TestArray=ARRAY(0x8141354)
+-------------------------------------------------------------------------+
Explanations
+-------------------------------------------------------------------------+
We see that weaken is not applied on a tied variable. I've been
searching in source code and calls goes like this :
Scalar::Util::weaken -> sv_rvweaken -> Perl_sv_rvweaken
+-------------------------------------------------------------------------+
Scalar::Util::weaken source code
+-------------------------------------------------------------------------+
void
weaken(sv)
SV *sv
PROTOTYPE: $
CODE:
#ifdef SvWEAKREF
sv_rvweaken(sv);
#else
croak("weak references are not implemented in this release of
perl");
#endif
We see clearly that it only calls sv_rvweaken from the perl source code.
So this method doesn't contain bugs.
We also finds that sv_rvweaken is associated to Perl_sv_rvweaken as
defined by embed.h
Let's look at this code
+-------------------------------------------------------------------------+
Perl_sv_rvweaken source code from sv.c
+-------------------------------------------------------------------------+
/*
=for apidoc sv_rvweaken
Weaken a reference: set the C<SvWEAKREF> flag on this RV; give the
referred-to SV C<PERL_MAGIC_backref> magic if it hasn't already; and
push a back-reference to this RV onto the array of backreferences
associated with that magic.
=cut
*/
SV *
Perl_sv_rvweaken(pTHX_ SV *sv)
{
SV *tsv;
if (!SvOK(sv)) /* let undefs pass */
return sv;
if (!SvROK(sv))
Perl_croak(aTHX_ "Can't weaken a nonreference");
else if (SvWEAKREF(sv)) {
if (ckWARN(WARN_MISC))
Perl_warner(aTHX_ packWARN(WARN_MISC), "Reference is
already weak");
return sv;
}
tsv = SvRV(sv);
sv_add_backref(tsv, sv);
SvWEAKREF_on(sv);
SvREFCNT_dec(tsv);
return sv;
}
+-------------------------------------------------------------------------+
Conclusion
+-------------------------------------------------------------------------+
The bug is in Perl_sv_rvweaken there :
if (!SvOK(sv)) /* let undefs pass */
return sv;
This code should be modified like this :
if (!SvOK(sv)) /* undef var or tied object or something else */
if (SvMAGIC(sv)) {
//********************************************/
//********************************************/
//********************************************/
//APPLY WEAKEN HERE (Which I don't know how)
//********************************************/
//********************************************/
//********************************************/
} else {
return sv;
}
}
Thank you
Philippe Cote
Centre de genomique fonctionnelle du Canada