File Coverage

blib/lib/Schedule/Load/Safe.pm
Criterion Covered Total %
statement 33 48 68.7
branch 8 18 44.4
condition 2 9 22.2
subroutine 6 7 85.7
pod 0 2 0.0
total 49 84 58.3


line stmt bran cond sub pod time code
1             # See copyright, etc in below POD section.
2             ######################################################################
3              
4             package Schedule::Load::Safe;
5             require 5.004;
6              
7 2     2   56040 use Safe;
  2         105621  
  2         163  
8              
9 2     2   26 use strict;
  2         5  
  2         97  
10 2     2   12 use vars qw($VERSION $Debug);
  2         4  
  2         122  
11 2     2   12 use Carp;
  2         4  
  2         1351  
12              
13             ######################################################################
14             #### Configuration Section
15              
16             $VERSION = '3.064';
17              
18             ######################################################################
19             #### Creators
20              
21             sub new {
22 2     2 0 925 my $proto = shift;
23 2   33     23 my $class = ref($proto) || $proto;
24 2         13 my $self = {
25             _cache => {},
26             cache_max_entries => 1000, # Maximum size of the cache (so we don't run out of memory)
27             @_,};
28 2         8 bless $self, $class;
29 2         8 return $self;
30             }
31              
32             ######################################################################
33             #### Evaluation
34              
35             sub _cache_check {
36 0     0   0 my $self = shift;
37 0 0       0 if (keys (%{$self->{_cache}}) > $self->{cache_max_entries}) {
  0         0  
38             # For speed, rather than a single entry, delete random ~10% of entries.
39 0         0 foreach my $key (keys %{$self->{_cache}}) {
  0         0  
40 0 0       0 if (rand(10)<=1.0) {
41 0         0 delete $self->{_cache}{$key};
42             }
43             }
44             }
45             }
46              
47             sub eval_cb {
48 4008     4008 0 284649 my $self = shift;
49 4008         5382 my $subref = shift;
50 4008         7650 my @subargs = @_;
51             # Call &$subref($subargs) in safe container
52 4008 100       7932 if (ref $subref) {
53 3         9 return $subref->(@subargs);
54             } else {
55 4005 100       15918 if (!exists $self->{_cache}{$subref}) {
56 2003         12587 my $compartment = new Safe;
57 2003         2479624 $compartment->permit(qw(:base_core));
58 2003         17009 $@ = "";
59 2003         6277 my $code = $compartment->reval($subref);
60 2003 50 33     1734101 if ($@ || !$code) {
61 2003 100       342748 print "eval_match: $@: $subargs[0]\n" if $Debug;
62 2003         9961 $self->{_cache}{$subref} = undef;
63 2003         14437 return undef;
64              
65             }
66 0         0 $self->_cache_check();
67 0         0 $self->{_cache}{$subref} = $code;
68             }
69 2002         2736 my $code = $self->{_cache}{$subref};
70 2002 50       5306 return undef if !defined $code;
71 0           my $result = $code->(@subargs);
72 0 0 0       if ($Debug && $Debug>1) { # Try again in non-safe container
73 0           my $dcode = eval($subref);
74 0           my $dresult = $dcode->(@subargs);
75 0 0         die "%Error: Safe mismatch: '$result' ne '$dresult'\n" if $dresult ne $result;
76             }
77 0           return $result;
78             }
79             }
80              
81             ######################################################################
82             ######################################################################
83             1;
84             __END__