develooper Front page | perl.perl5.porters | Postings from August 2011

IN SEARCH OF: The definitive treatise on the "private" OK flags (SVp*OK)

Thread Next
From:
Chip Salzenberg
Date:
August 12, 2011 21:20
Subject:
IN SEARCH OF: The definitive treatise on the "private" OK flags (SVp*OK)
Message ID:
CANSL5VHD_ncQmqo8b0E2_A+f5panU4FFDpmNYacfF0mbqmp-dQ@mail.gmail.com
/me lights the Tim Toady Signal
(I don't think this bug goes back that far, but I want to understand the
design principles involved)

Consider:

  sub f { my $p = $_[0]; $p }
  my $x = 'banana';
  $x =~ /.a/g;
  f(pos $x) == 2 or die;

Run this under -Dts and you'll see what looks completely normal:

(/tmp/pat:17) padsv($x)
    =>  *  PVMG("banana"\0)
(/tmp/pat:17) pos
    =>  *  PVLV()
(/tmp/pat:17) gv(main::f)
    =>  *  PVLV()  GV()
(/tmp/pat:17) entersub
    =>  PVLV()
[...]
(/tmp/pat:12) aelemfast
    =>  PVLV()
(/tmp/pat:12) padsv($p)
    =>  PVLV()  UNDEF
(/tmp/pat:12) sassign
    =>  PVNV(4)

However, this is a lie.  NOK is not set on this value.  IOK is not set on
this value.  pIOK is set.  Devel::Peek or sv_dump() tells the tale:  This is
bad, broken, and a consequence of code in the mg_set subsystem since, more
or less, 2004.  Maybe before.

How this has escaped causing serious malfunction I don't know, though I have
one example below.  To fix this I need to be sure I know everything there is
to be known about how the private flags are SUPPOSED to work.

Now watch:

(/tmp/pat:12) nextstate
    =>
(/tmp/pat:13) pushmark
    =>  *
(/tmp/pat:13) padsv($p)
    =>  *  PVNV(4)
(/tmp/pat:13) return
    =>  PVNV(4)
(/tmp/pat:17) const(IV(4))
    =>  PVNV(4)  IV(4)
(/tmp/pat:17) eq
    =>  SV_YES

Guess what.  Those two values are actually both integers - they both
actually have valid SvIVX values.  But the flags are wrong.  Viz:

(gdb) p sv_dump(left)
SV = PVNV(0x83affec) at 0x83b1bd8
  REFCNT = 1
  FLAGS = (TEMP,pIOK)
  IV = 2
  NV = 0
  PV = 0

The pp_eq() function doesn't see IOK on the PVNV (only pIOK which doesn't
count), so the IVX equality optimization code just gets skipped.  Instead,
the generic NV equality code gets called.  And that probably only works
because when you want an NV, a cached private integer is assumed to be a
good substitute.

I think we have a situation where every value coming back from magic - every
tie and every value that comes from a MAGIC-get-based feature of Perl - is
getting the wrong flags set, and is thus at the very least being subjected
to extra conversions.  Perhaps wrong ones.  I know I've written code that
assumes that after you call mg_get() you can call SvIOK() for example, to
see if you got a (possibly magic) integer.  Now it seems that trick NEVER
works...

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About