develooper Front page | perl.perl5.porters | Postings from February 2012

Re: [perl #109726] PL_sv_undef loses identity

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
February 9, 2012 06:13
Subject:
Re: [perl #109726] PL_sv_undef loses identity
Message ID:
20120209141311.GI9069@plum.flirble.org
I've been thinking about this for a bit. I've just remembered an
important part. Right now, PL_sv_placeholder is in perlvars.h, *not*
intrpvar.h:

/* Restricted hashes placeholder value.
 * The contents are never used, only the address. */
PERLVAR(G, sv_placeholder, SV)

It's a global, not per-interpreter. If I understand things correctly, the
address &PL_sv_placeholder is never actually *returned* anywhere - it's
used to compare against. That means that nothing can fiddle with its
reference count, or accidentally upgrade it, bless it, or anything else.

(I think that Juerd did a lightning talk on undef abuse that included
demonstrating how to bless PL_sv_undef)

Whilst that can be solved by making it per-interpreter, I'm not sure what
interesting side effects will be knock ons from there. eg

On Mon, Feb 06, 2012 at 12:59:33PM +0000, Zefram wrote:
> Dave Mitchell wrote:
> >fetched in lvalue context (e.g. \$_[0]), av_fetch() converts PL_sv_undef
> >int the slot into a real SV:
> 
> It's another special-case use of PL_sv_undef to mean something
> other than the Perl-visibile standard undef value.  Another case for
> PL_sv_placeholder?

This would mean that &PL_sv_placeholder has the potential to be returned
by APIs that didn't use to. Whilst this is sort of the same problem as
PL_sv_undef propagating further than we might like

a) &PL_sv_undef is well known to XS code that wants to care about it
b) Accidentally propagating PL_sv_placeholder onwards to places where it
   shouldn't be (eg in the front door of the hash APIs) will cause
   "interesting" bugs.

   Historically, PL_sv_placeholder was introduced for 5.8.1. 5.8.0 added
   restricted hashes (gah) and the placeholders, but used PL_sv_undef for
   the placeholder value. Which broke existing working XS code which stored
   PL_sv_undef in hashes, mostly as a token value where the key was
   important.

On Fri, Dec 30, 2011 at 01:40:12PM -0800, Father Chrysostomos via RT wrote:

> There is also this interesting bit:
> 
> 	    else if (o->op_type != OP_METHOD_NAMED
> 		&& cSVOPo->op_sv == &PL_sv_undef) {
> 		/* PL_sv_undef is hack - it's unsafe to store it in the
> 		   AV that is the pad, because av_fetch treats values of
> 		   PL_sv_undef as a "free" AV entry and will merrily
> 		   replace them with a new SV, causing pad_alloc to think
> 		   that this pad slot is free. (When, clearly, it is not)
> 		*/
> 		SvOK_off(PAD_SVl(ix));
> 		SvPADTMP_on(PAD_SVl(ix));
> 		SvREADONLY_on(PAD_SVl(ix));
> 
> I don't believe &PL_sv_placeholder is ever accessible to Perl, so using
> that instead of &PL_sv_undef in pad.c would allow XS modules to provide
> an OP_CONST that actually returns &PL_sv_undef.

This is still somewhat wooly in my head, but there are several levels in the
hierarchy of what AVs are used for

0:   !AvREAL() && !AvREIFY() just the stacks? [and @DB::args currently]
1:   !AvREAL() && AvREIFY()  @_ [and @DB::args should be here]
2:   Pads
2.5: other AVs seen only by C and XS code that can have AVs, HVs etc directly
     in them
3:   AVs visible to Perl code - ie via a reference, and containing only
     scalars and *references* to nested containers


As far as can work out, the stacks store garbage rather than any sort of
pointer for empty parts. From this:

	    else {
		newmax = key < 3 ? 3 : key;
		MEM_WRAP_CHECK_1(newmax+1, SV*, oom_array_extend);
		Newx(AvALLOC(av), newmax+1, SV*);
		ary = AvALLOC(av) + 1;
		tmp = newmax;
		AvALLOC(av)[0] = &PL_sv_undef;	/* For the stacks */
	    }
	    if (AvREAL(av)) {
		while (tmp)
		    ary[--tmp] = &PL_sv_undef;
	    }

I still don't understand that part commented "For the stacks". Why does
the first element, but the first element *only* need to be a valid pointer?


Anyway, I suspect that there's low risk of problems elsewhere if the Pads
switched to using PL_sv_placeholder for a free slot, as they are only
supposed to be accessed via our APIs, which would never actually *return*
it. And Pads are already somewhat insane with their manual reference
counting fakery.

I'm concerned that there would be odd strange breakages if arrays (more
generally) started using PL_sv_placeholder because it would start escaping.

But I suspect the only way to get a handle on *that* would be to tweak the
core and then smoke CPAN against it.

Nicholas Clark

Thread Previous | 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