develooper Front page | perl.perl5.porters | Postings from December 2005

PL_sv_undef in OPCONST in ithreads broken

Thread Next
From:
Nicholas Clark
Date:
December 26, 2005 14:42
Subject:
PL_sv_undef in OPCONST in ithreads broken
If you generate an OPCONST whose value is a pointer to PL_sv_undef, then it
seems that it can trigger a bug.

My somewhat esoteric test case is:

# use strict;

#use Devel::Peek;
BEGIN {
    $::{Undef} = \undef;
    # Dump \undef;
}

if ($$) {
} else {
  "!$no\n";
}

$undef = Undef;
unless ($undef) {
  print "ok 16\n";
} else {
  print "not ok 16 # \$undef='$undef'\n";
      # Dump \Undef; Dump \undef;
}
__END__


Yes, it's using the new fangled references in typeglobs, but I suspect that
the bug can be triggered with XS code, or anything else that can manage to
get PL_sv_undef into the op_sv of a CONSTOP.

The output I see is

not ok 16 # $undef='
'

It seems that the PAD slot used by the constant that replaces Undef in
C<$undef = Undef;> is double booked by the last pad temporary used by"!$no\n";


$ ./perl -Ilib -MO=Concise t.pl
h  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 5 t.pl:9) v ->3
-     <1> null vK/1 ->6
4        <|> cond_expr(other->5) vK/1 ->s
-           <1> ex-rv2sv sK/1 ->4
3              <#> gvsv[*$] s ->4
-           <@> scope vK ->-
5              <0> stub v ->6
z           <@> leave vKP ->6
s              <0> enter v ->t
t              <;> nextstate(main 3 t.pl:11) v ->u
-              <1> ex-stringify vK/1 ->z
-                 <0> ex-pushmark s ->u
y                 <2> concat[t4] sKS/2 ->z
w                    <2> concat[t3] sK/2 ->x
u                       <$> const[PV "!"] s ->v
-                       <1> ex-rv2sv sK/1 ->w
v                          <#> gvsv[*no] s ->w
x                    <$> const[PV "\n"] s ->y
6     <;> nextstate(main 5 t.pl:14) v ->7
9     <2> sassign vKS/2 ->a
7        <$> const[PV "\n"] s ->8
-        <1> ex-rv2sv sKRM*/1 ->9
8           <#> gvsv[*undef] s ->9
a     <;> nextstate(main 8 t.pl:15) v ->b
-     <1> null vK/1 ->h
d        <|> cond_expr(other->e) vK/1 ->i
c           <1> not sK*/1 ->d
-              <1> ex-rv2sv sK/1 ->c
b                 <#> gvsv[*undef] s ->c
-           <@> scope vK ->-
-              <0> ex-nextstate v ->e
g              <@> print vK ->h
e                 <0> pushmark s ->f
f                 <$> const[PV "ok 16\n"] s ->g
r           <@> leave vKP ->h
i              <0> enter v ->j
j              <;> nextstate(main 6 t.pl:18) v ->k
q              <@> print vK ->r
k                 <0> pushmark s ->l
-                 <1> ex-stringify sK/1 ->q
-                    <0> ex-pushmark s ->l
p                    <2> concat[t11] sKS/2 ->q
n                       <2> concat[t10] sK/2 ->o
l                          <$> const[PV "not ok 16 # $undef='"] s ->m
-                          <1> ex-rv2sv sK/1 ->n
m                             <#> gvsv[*undef] s ->n
o                       <$> const[PV "'\n"] s ->p
t.pl syntax OK




The problem is here:


Hardware watchpoint 17: *(struct sv **) 136264512

Old value = (struct sv *) 0x81f5624
New value = (struct sv *) 0x81f7fcc
Perl_av_store (my_perl=0x81f5000, av=0x81f734c, key=13, val=0x81f7fcc)
    at av.c:335
335         if (SvSMAGICAL(av)) {
(gdb) where
#0  Perl_av_store (my_perl=0x81f5000, av=0x81f734c, key=13, val=0x81f7fcc)
    at av.c:335
#1  0x080e733f in Perl_av_fetch (my_perl=0x81f5000, av=0x81f734c, key=13,
    lval=1) at av.c:241
#2  0x080b1c30 in Perl_pad_alloc (my_perl=0x81f5000, optype=5, tmptype=512)
    at pad.c:433
#3  0x080af16a in Perl_peep (my_perl=0x81f5000, o=0x820fb4c) at op.c:6789
#4  0x0809fdf8 in Perl_newPROG (my_perl=0x81f5000, o=0x820ff0c) at op.c:1970
#5  0x08098bee in Perl_yyparse (my_perl=0x81f5000) at perly.y:100
#6  0x08064f53 in S_parse_body (my_perl=0x81f5000, env=0x0,
    xsinit=0x805f0ec <xs_init>) at perl.c:2170
#7  0x08063af3 in perl_parse (my_perl=0x81f5000, xsinit=0x805f0ec <xs_init>,
    argc=3, argv=0xbfbfebc0, env=0x0) at perl.c:1555
#8  0x0805f025 in main (argc=3, argv=0xbfbfebc0, env=0xbfbfebd0)
    at perlmain.c:101
(gdb) call Perl_sv_dump(my_perl, (struct sv *) 0x81f5624)
SV = NULL(0x0) at 0x81f5624
  REFCNT = 2147483646
  FLAGS = (PADTMP,READONLY)
(gdb) call Perl_sv_dump(my_perl, (struct sv *) 0x81f7fcc)
SV = NULL(0x0) at 0x81f7fcc
  REFCNT = 1
  FLAGS = ()


What has happened is that the array used for the pad was happily and
accurately storing the value PL_sv_undef, which by now has also (correctly)
acquired the flag PADTMP because in use as a pad temporary. (*This* pad
temporary).

Working back up the last 3 calls of that traceback, pad_alloc does:

	    sv = *av_fetch(PL_comppad, PL_padix, TRUE);
	    if (!(SvFLAGS(sv) & (SVs_PADTMP | SVs_PADMY)) &&
		!IS_PADGV(sv) && !IS_PADCONST(sv))
		break;

av_fetch finds the (correct, put there) value PL_sv_undef:

    if (AvARRAY(av)[key] == &PL_sv_undef) {
    emptyness:
	if (lval) {
	    sv = NEWSV(6,0);
	    return av_store(av,key,sv);
	}
	return 0;
    }

and interprets it as an unused array slot. (D'oh!)
So it calls into av_store, to store the value:

    ary[key] = val;

and bang! the correctly stored PL_sv_undef is replaced by a nice new undefined
scalar, which doesn't have PADTMP set, which makes pad_alloc think that the
pad slot is free.


I'm not sure what the solution to this is. I wonder if the cheap hack is
to always "copy" PL_sv_undef into the pad. But long term, should
PL_sv_placeholder be used in place of PL_sv_undef for the AV "not allocated"
marker?

Nicholas Clark

PS TODO item - can that recursive call into av_store be avoided in the common
   case, as I managed for hv_fetch?

Thread Next


Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About