Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Accessing 'my' variables from another file

Tags:

perl

We have at work a Perl script which is used to perform maintenance. I needed to modify it to handle more tasks. The problem is that the script is compiled and the source was lost long ago.

I tried to use B::Deparse in order to recreate the file but Deparse is not perfect and the output is broken (and very large ~5000 lines of deparsed code).

After reading the deparsed code I found that I need to modify one function. The compiled script loads a plain-text script module, so I altered the module to override the function and perform the task I need it to perform. The problem now is that I cannot access the main script "my" variables.

Here's an example:

# main.pl

my $a = 1;

sub call_me {
    print "unmodified";
}

use MOD;

call_me;


MOD.pm
package MOD;

main::{'call_me'} = sub {
    print "\$main::a = $main::a\n";
}

The result is: "$main::a =" instead of getting the real value.

Thanks in advance.

like image 689
user1247066 Avatar asked Jul 13 '12 20:07

user1247066


1 Answers

The short answer is that variables declared with my are not accessible outside of their lexical scope. If you can't change the declaration to "our" (because of the crazy "compiled" nature of the original script), you aren't yet out of luck. Perl almost always provides a way around these types of things.

In this case, you can install the PadWalker module and do something like this (here's a tweaked version of your originally posted code):

The main.pl script:

my $a = 1;

sub call_me {
    print "unmodified: $a";
}

use MOD;

call_me;

And then your module:

package MOD;

# closed_over($code_ref) returns a hash ref keyed on variable
# name(including sigil) with values as references to the value
# of those variables
use PadWalker qw(closed_over);

{
    # grab a reference to the original sub
    my $orig = \&main::call_me;

    # no need to use the symbol table, a glob reference is fine
    # but you can't use sub main::call_me { ... } either
    *main::call_me = sub {
        my $a = closed_over($orig)->{'$a'};
        print "\$main::a = $$a\n";
    }
}
like image 140
Brian Phillips Avatar answered Sep 24 '22 05:09

Brian Phillips