Thursday, February 5, 2009

Hacking the Perl Symbol Table

At work today, I gave the inaugural "engineering minute" presentation at the bi-weekly "engineering all-hands" meeting. In fact, the whole idea of the "engineering minute" came from some code my colleague Russ and I wrote a few weeks ago. I had a simple problem, and we decided to solve it by hacking the Perl symbol table in a clever and fun but not quite opaque manner.

For those of you not entirely in the loop, the symbol table is essentially a list of functions, variables, and other objects, that is used by the program to figure out where in the computer's memory to locate that particular object.

In this case, I was using Perl's symbol table to rename functions and replace them with something else. That "something else" was a wrapper function that would perform some checks on the arguments that were passed to the original function and then decide whether to go forward with executing the function or warn the user that something evil has happened.

It turns out hacking the symbol table for this purpose is actually quite easy if you go about it the right way. Since I'm not at liberty to share company code with the world, I'll instead show how I did it while writing the Tie::Hash::Expire module, which I plan on uploading to CPAN soon.


# Integrate cache expiry via the symbol table.
for my $f (qw(FETCH EXISTS))
{
eval qq
{
*Tie::Hash::Expire::_uncached_$f = *Tie::Hash::Expire::$f;
undef *Tie::Hash::Expire::$f;
*Tie::Hash::Expire::$f = sub
{
\$_[0]->_update_cache(\$_[1]);
&_uncached_$f;
};
};
}


Of course, this only wraps the
FETCH
and
EXISTS
hash access functions, but that's the point: you only wrap what you need to wrap, and in so doing, you avoid duplicating code and risking doing the right thing in one place and the wrong thing in another.