>>>>> "AT" == Alexey Tourbin <[EMAIL PROTECTED]> writes:
AT> Brief description: consequent svref_2object calls produce wrong AT> B objects in certain cases. Detailed explanation and test cases AT> are available via the following links: AT> http://www.nntp.perl.org/group/perl.perl5.porters/96593 AT> http://www.nntp.perl.org/group/perl.perl5.porters/96600 SMcC> I think your diagnosis is correct. The B module in general, and SMcC> svref_2object in particular, does not increase the reference SMcC> count of the SV and OP objects the B::SV and B::OP proxies point SMcC> to, so bad things happen if the proxy is used after the SMcC> underlying object is freed. (I bet with more experimentation you SMcC> could get a segfault, for instance). AT> Okay, thanks a lot for this clarification. Unfortunately I don't quite AT> grok reference counting mechanism in Perl (for now). I just have a code AT> that has a kludge that apparently fixes the mechanism for perl-5.8.x. AT> The code is as follows: AT> [...] [snip] AT> To examine the real code, you may want to take a look at AT> http://search.cpan.org/dist/rpm-build-perl/ (only PVMG version AT> strings seems to break things). My original post has a very AT> simple example, though. I think I can explain more easily what's going on in your simple example. For the readers playing along at home, your short example was: AT> my $v1 = 0.17; AT> my $v2 = 0.1.7; AT> sub get_sv { AT> my $v = shift; AT> my $sv = svref_2object(\$v); AT> return $sv; AT> } AT> Dump get_sv($v1); AT> get_sv($v2); AT> Dump get_sv($v1); The first Dump shows that its argument is a reference to a B::NV object, while the second shows its to be a reference to a B::PVMG. What I think may be confusing about this example is that get_sv doesn't actually tell you about its argument SV. Rather, it returns a B::SV object that describes its local $v variable. When, as in the unmodified example, no reference to $v escapes the subroutine (the reference count of $v is 1 on leaving the subroutine), perl doesn't bother to free the local; rather, it keeps it around to reuse the next time the subroutine is called. This allows it to save time that would otherwise be spent reallocating and "upgrading" the local on the next sub call; it assumes that if you made an SV big and complicated on one invocation, you likely will again. Thus all three calls to get_sv return B::SV objects referring to the same SV. When a PVMG is passed in the second get_sv() call, $v is upgraded to accommodate it, and it stays upgraded for the third call. If you change the code to pass the variable by reference, i.e. sub get_sv { my $vref = shift; my $sv = svref_2object($vref); return $sv; } Dump get_sv(\$v1); get_sv(\$v2); Dump get_sv(\$v1); you'll see that $v1 stays an NV. To sharpen what I was saying above, I don't think your bug comes from an SV being freed to soon; rather, the SV is being reused unexpectedly. Making another reference to the variable is a workaround because it disables the reuse optimization; perl allocates a new SV, which your code handles better. On to how you might fix your real bug (note I've added a bit more context in the first sub): AT> sub extract_version { AT> [...] AT> my $version = ....; AT> [...] AT> use B qw(svref_2object); AT> our $perlbug32967 = \$version; AT> my $v = sv_version(svref_2object(\$version)); AT> # process $v AT> [...] AT> use B qw(class); AT> sub sv_version ($) { AT> my $sv = shift; AT> my $class = class($sv); AT> if ($class eq "IV" or $class eq "PVIV") { AT> return $sv->int_value; AT> } AT> if ($class eq "NV" or $class eq "PVNV") { AT> return $sv->NV; AT> } AT> if ($class eq "PVMG") { AT> for (my $mg = $sv->MAGIC; $mg; $mg = $mg->MOREMAGIC) { AT> next if $mg->TYPE ne "V"; AT> my @v = $mg->PTR =~ /(\d+)/g; AT> return $v[0] + $v[1] / 1000 + $v[2] / 1000/1000; AT> } AT> } AT> if ($sv->can("PV")) { AT> my $v = $sv->PV; AT> if ($v =~ /^\s*\.?\d/) { AT> $v =~ s/_//g; AT> return $v + 0; AT> } AT> } AT> return undef; AT> } I think the real problem with sv_version is that its logic is wrong: it's trying to switch on the representation type of the SV, rather than the contents. Just because an SV is a PVMG doesn't mean it has magic now (in particular, because SVs can't be "downgraded"). For a single invocation that shows this problem, try: my $x = 3; study $x; $x = 4; print sv_version(svref_2object(\$x)), "\n"; The first three lines make $x a PVMG with no string value or V magic whose value is stored as an integer, but your code skips the branch that would have called $sv->int_value because it's deciding based on the SV's class. I'd suggest testing in the following order: if (SV has "V" magic) { parse V-string } if (SV is IOK) { use int_value } if (SV is NOK) { use NV } if (SV is POK) { parse PV } Hope this helps, -- Stephen