I found that a modified version of scrub_package
(written by Mark-Jason Dominus and described in perlfaq7)
works correctly and more efficiently than
Apache::PerlRun->flush_namespace

Here is the original scrub_package subroutine:

             sub scrub_package {
                 no strict 'refs';
                 my $pack = shift;
                 die "Shouldn't delete main package"
                     if $pack eq "" || $pack eq "main";
                 my $stash = *{$pack . '::'}{HASH};
                 my $name;
                 foreach $name (keys %$stash) {
                     my $fullname = $pack . '::' . $name;
                     # Get rid of everything with that name.
                     undef $$fullname;
                     undef @$fullname;
                     undef %$fullname;
                     undef &$fullname;
                     undef *$fullname;
                 }
             }

Instead of the line
          undef &$fullname;
which undef's the source subroutine, one should use
          *{$fullname}=sub {};
This fix is obvious because that is the way how a code alias is
generated in the first place. In order to undef this alias,
just let it point to an anonymous subroutine which does nothing.

Since this does not involve B.pm, it is more efficient than

Apache::PerlRun->flush_namespace

Also, I never got Apache::PerlRun->flush_namespace to work in
my case. Looking at the source used:

sub undef_cv_if_owner {
    return unless $INC{'B.pm'};
    my($package, $cv) = @_;
    my $obj    = B::svref_2object($cv);
    my $stash  = $obj->GV->STASH->NAME;
    return unless $package eq $stash;
    undef &$cv;
}

For one thing $package never equals $stash. Further, I believe that
the last line
        undef &$cv;
suffers from the same bug found in the original version of scrub_package.
I.e., it undef's the source subroutine!

Thanks for your attention.

Richard Chen

Richard Chen wrote:
> 
> Unfortunately, the crucial part about clearing/removing
> subroutine alias does not work when using
>         Apache::PerlRun->flush_namespace('Q')
> I suspect this is a bug in PerlRun. Here is the demo program
> (It can be run from the command line)
> 
> $ cat tmp.pl
> #!/usr/bin/perl -w
> use strict;
> use Apache::PerlRun;
> print "Content-type: text/plain\n\n";
> %Q::in=();
> $Q::in{first_name}='first_name';
> *Q::hello=\&hello;
> print "here is the symbol table\n";
> print join("\n", map { "\$Q::{$_}=$Q::{$_}" } keys %Q::),"\n";
> print "\nbefore clear name space, \%Q::in is\n";
> print join("\n", map { "\$Q::in{$_}=$Q::in{$_}" } keys %Q::in),"\n";
> print "\nbefore clear name space, calling \&Q::hello yields\n";
> &Q::hello();
> print "-------------Now clear package name space---------\n";
> Apache::PerlRun->flush_namespace('Q');
> print "here is the symbol table\n";
> print join("\n", map { "\$Q::{$_}=$Q::{$_}" } keys %Q::),"\n";
> print "\nafter name space, \%Q::in is\n";
> print join("\n",map { "\$Q::in{$_}=$Q::in{$_}" } keys %Q::in),"\n";
> print "\nafter clear name space, calling \&Q::hello yields\n";
> &Q::hello();
> sub hello { print "hello\n"; }
> 
> $ ./tmp.pl
> here is the symbol table
> $Q::{hello}=*Q::hello
> $Q::{in}=*Q::in
> 
> before clear name space, %Q::in is
> $Q::in{first_name}=first_name
> 
> before clear name space, calling &Q::hello yields
> hello
> -------------Now clear package name space---------
> Odd number of elements in hash assignment at 
>/usr/lib/perl5/site_perl/5.005/i586-linux/Apache/PerlRun.pm line 310.
> Use of uninitialized value at 
>/usr/lib/perl5/site_perl/5.005/i586-linux/Apache/PerlRun.pm line 310.
> here is the symbol table
> $Q::{hello}=*Q::hello
> $Q::{in}=*Q::in
> 
> after name space, %Q::in is
> Use of uninitialized value at ./bar.cgi line 19.
> $Q::in{}=
> 
> after clear name space, calling &Q::hello yields
> hello
> 
> Note in particular that the value for &Q::hello still exists.
> Since you have pointed out that symbol table is constructed at
> compile time, at least the clean up of name space should make this
> value undefed.
> 
> Doug MacEachern wrote:
> >
> > On Mon, 1 May 2000, Richard Chen wrote:
> >
> > > Hello,
> > >       I am having a problem clearing variables and aliases
> > > in a temporary package name space. The source of the problem
> > > is in making legend cgi scripts work under Apache::Registry.
> > > But the problem can be isolated and shown by the following
> > > demo program:
> > >
> > > $ cat foo.cgi
> > > #!/usr/bin/perl -w
> > > use strict;
> > > use Symbol qw(delete_package);
> > > print "Content-type: text/plain\n\n";
> > > %Q::userdata=();
> > > $Q::userdata{first_name}='first_name';
> > > $Q::userdata{last_name}='last_name';
> > > *Q::hello=\&hello;
> > > print "here is the symbol table\n";
> > > while (my($k,$v)=each %Q::) {
> > >         print "$k => $v\n";
> > > }
> > > delete_package('Q');
> > > sub hello {
> > >         print "hi\n";
> > > }
> > >
> > > The first time it runs, it yields:
> > >
> > > here is the symbol table
> > > userdata => *Q::userdata
> > > hello => *Q::hello
> > >
> > > But there after, modperl shows emtpy symbol table.
> >
> > the problem is that Perl creates symbol table references at compile time,
> > Symbol::delete_package() wipes those references out of existence.
> > try using Apache::PerlRun->flush_namespace('Q'), which clears just
> > the values, and leaves the references in tact.

Reply via email to