develooper Front page | perl.perl5.porters | Postings from March 2006

fanciful: local implemented through "masking containers"

David Nicol
March 30, 2006 10:49
fanciful: local implemented through "masking containers"
Message ID:
On 3/30/06, Nicholas Clark <> wrote:
> On Wed, Mar 29, 2006 at 05:33:27PM -0600, David Nicol wrote:
> > 1:  a new data structure, the "masking hash", that has an attribute
> > that says what other (masking or non-masking) hash to look in when looking for a
> > nonexistent key

> > Given masking-hash, C<local> could be rewritten using maskinghash instead pf
> > the current implementation and MJD's scalar localization tieing
> > exploits would all
> > fail.
> I don't think that this would work, as it only affects where the lookup of
> a particular name takes you. local needs to be able to localise specific
> value containers directly, rather than just the name. For example, this works:
> $ perl -lwe 'local $ARGV[1] = "Boo!"; print "@ARGV"' a b c
> a Boo! c
> Nicholas Clark

Right.  Masking arrays and masked scalars (Hi ho, Silver!) would need
to exist too.  Local would determine the final container and mask it.

In that one-liner, *ARGV->array would get replaced with a maskable
array with its parent attribute set to the old *ARGV->array and ->[1]
set to the string.  At the end of the scope, *ARGV->array would be
replaced with the old value.

This is how I thought local worked, before I found out how local really works,
which is simpler but involves hidden FETCH and STORE operations.

Masking-local would avoid the fetching and storing on the hidden values, since
the container is getting changed instead of the value, at the cost of having
to check for a mask hit and then traverse parent pointers on every access  to
non-masked data.

array masks would usually be sparse, so using the same mechanism for
storing the mask as with a masked hash would make sense.

The whole idea would be a net efficiency loss, but it would avoid
the "remotely tied global localized with a sigyll exploit."  But no
better than always localizing globs when you must localize does.

bash-3.00# cat -n localploit
     2  use Carp;
     3  use Tie::Array;
     5  @ar=qw/a b c/;
     6  local $ar[1]="Boo!";
     7  print"@ar";
     9  BEGIN{
    10   push@X::ISA,"Tie::StdArray";
    11   tie@ar,"X";
    12   sub X::FETCH{confess "ha ha ha"}
    13  }
bash-3.00# perl localploit
ha ha ha at localploit line 12
        X::FETCH('X=ARRAY(0x8098948)', 1) called at localploit line 6

bash-3.00# cat -n localploit_defeated
     2  use Carp;
     3  use Tie::Array;
     5  @ar=qw/a b c/;
     6  # local *ar[1]="Boo!"; ### syntax error
     7  local *ar=[qw/a Boo! c/];
     8  print"@ar\n";
    10  BEGIN{
    11   push@X::ISA,"Tie::StdArray";
    12   tie@ar,"X";
    13   sub X::FETCH{confess "ha ha ha"}
    14  }
bash-3.00# perl localploit_defeated
a Boo! c

I guess a pure-perl masked array might get used like

      @ar=qw/a b c/;
      # INSTEAD OF:  local $ar[1]="Boo!";
         tie my @ar, "Tie::MaskedArray", parent => \@ar, mask => { 1 => "Boo!"};
      print "@ar\n";

Anyone want me to add such a thing to my CPAN directory full of stupid
tie tricks?

David L Nicol
"the opportunity of making good with a hard undertaking - one that had
been held impossible of realization - would be a strong asset to the
firm's reputation" -- William Russell, 1860 Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About