develooper Front page | perl.perl5.porters | Postings from July 2013

[idea] perl vm state "pinning/snapshot" support

From:
Kent Fredric
Date:
July 17, 2013 00:24
Subject:
[idea] perl vm state "pinning/snapshot" support
Message ID:
CAATnKFAO6e9y15Jbhc6rDf92Uksyq+p+RgNJvQvwbYJgtYoReg@mail.gmail.com
Something that has been bouncing around in my head for a few weeks, as
something that would be "nice", would be the ability
to make a "frozen" interpreter state, where all package namespace
states and soforth were frozen and marked.

And then all successive changes to the global perl state was cow'd
relative to that.

My usecase is really the present situation we have with various
modules that call <require> for us, and a present concern that modules
may fail to compile, but still leave the global interpreter in a
broken state, with some namespaces populated and others not, requiring
crazy heuristics to try to determine if a module loaded or not

For instance:  https://rt.cpan.org/Ticket/Display.html?id=63013

The idea would be you could create a snapshot marker, and then revert
to that state if things went bad:

sub require {
  my ($path) = @_;
  my $vm = vm_snapshot;
  require $path;
  if ( $@ ) {
    $vm->revert;
    return 'fail';
  }
  $vm->replace;
  return 'ok';
}

Here, if require $path failed, flow control to the resulting vm would
be as if you'd done.

sub require {
  my ( $path )  = @_;
  return 'fail';
}

And if $path did not fail, the resulting vm becomes the "new" VM, and
the snapshot is discarded:

sub require {
  my ( $path )  = @_;
  my $vm = ...;
  require $path;
  if ( $@ ) { ... }
  return 'ok';
}


so vm->revert makes the parent jump from the line that called
vm_snapshot to the line that called vm->revert
and vm->replace functions as if no snapshot had been taken.

There's still a few logical problems to iron out with this model
however, for instance, after calling vm->revert, the value of $@
should roll back to the snapshotted version too, and all variables
defined/modified between making the snapshot and reverting it should
also "go out of scope".

Granted this sort of thing is pretty crazy, and I'm not sure its even
possible to do, but this seems less crazy than say, "Class::Unload",
which will not catch the many eclectic ways loading modules can mess
up global state.


__[ m.pl ]__
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use lib 'lib';
#use Module::Runtime qw( require_module );
local $@;
eval {
    require evil;  # require_module('evil') has the same problem
};
warn $@ if $@;

method();
__[ lib/evil.pm ]__
use warnings;
no strict 'refs';

# This is to step past things like Module::Runtime and proliferate
into any package in calling contexts.
for my $i ( 0 .. 20 ){
    my $pkg = [ caller($i) ]->[0];
    last unless $pkg;
    print "messing with : $pkg\n";
    *{$pkg . '::method'} = sub {
       print "this works :\\ \n";
    };
}

die;
__[ output ]__
messing with : main
messing with : main
Died at lib/evil.pm line 14.
Compilation failed in require at m.pl line 10.
this works :\


-- 
Kent

perl -e  "print substr( \"edrgmaM  SPA NOcomil.ic\\@tfrken\", \$_ * 3,
3 ) for ( 9,8,0,7,1,6,5,4,3,2 );"

http://kent-fredric.fox.geek.nz



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