Last active
August 29, 2015 13:56
-
-
Save avar/8809976 to your computer and use it in GitHub Desktop.
Some code snippets of code I'm using to detect when Mason clobbers subroutines in HTML::Mason::Commands during a request
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## Utility function to get a copy of subroutines in a given namespace: | |
| sub copy_of_code_symbols { | |
| my ($symbol_table) = @_; | |
| my %copy = map { | |
| +($_ => *{$symbol_table->{$_}}{CODE}); | |
| } grep { | |
| my $name = $_; | |
| # Maybe it's not a code symbol | |
| my $reftype = ''; | |
| eval { | |
| # Not all of them are globs, e.g. constants defined by | |
| # constant.pm. Easier just to check these with eval. | |
| $reftype = ref *{$symbol_table->{$name}}{CODE}; | |
| 1; | |
| } or do { | |
| my $error = $@ || "Zombie Error"; | |
| #use Data::Dump::Streamer; | |
| #Dump({error => [$name => $error => $symbol_table->{$name}]})->To(\*STDERR)->Out(); | |
| }; | |
| $reftype eq 'CODE'; | |
| } keys %$symbol_table; | |
| return \%copy; | |
| } | |
| # We'll set $EXECUTED_MASON if we executed a Mason page during the | |
| # request, $MASON_SUBS_AT_REQUEST_START is set after we finish this | |
| # request, or as a special case just after we fork the webserver | |
| # child: | |
| # Under Mason all templates are compiled into the | |
| # HTML::Mason::Commands namespace. We want to figure out the | |
| # difference between the symbols before and after all requests, so | |
| # we can report on any clobbered subroutines. | |
| if (MASON_DETECT_CLOBBERED_SUBROUTINES and $EXECUTED_MASON) { | |
| my (@sub_same, @sub_clobbered, @sub_added); | |
| my $subs_before = $MASON_SUBS_AT_REQUEST_START; | |
| my $subs_after = copy_of_code_symbols(\%HTML::Mason::Commands::); | |
| for my $sub (sort keys %$subs_after) { | |
| if (exists $subs_before->{$sub}) { | |
| # This request added a sub to HTML::Mason::Commands, | |
| # which is fine unless an existing sub was | |
| # clobbered. "Fine" here is relative, we'll eventually | |
| # end up with a *huge* symbol table, but who cares as | |
| # long as we don't have collisions... | |
| if ($subs_before->{$sub} != $subs_after->{$sub}) { | |
| push @sub_clobbered => $sub; | |
| } else { | |
| push @sub_same => $sub if DEBUG; | |
| } | |
| } else { | |
| push @sub_added => $sub if DEBUG; | |
| } | |
| } | |
| TELL "We went from <%d> to <%d> subs in HTML::Mason::Commands. That's <%d> added, <%d> are the same, <%d> were clobbered", | |
| scalar(keys %$subs_before), | |
| scalar(keys %$subs_after), | |
| scalar(@sub_added), | |
| scalar(@sub_same), | |
| scalar(@sub_clobbered) | |
| if DEBUG; | |
| if (@sub_clobbered) { | |
| warn "During this Mason request we clobbered one or more HTML::Mason::Commands subs\n" | |
| . "\n" | |
| . "We clobbered <" . scalar(@sub_clobbered) . "> of them: <" . join(", ", @sub_clobbered) . ">\n" | |
| . "\n" | |
| . "Note that the stack trace displayed here isn't significant, but\n" | |
| . "it should be fairly easy to find the symbol that's being\n" | |
| . "clobbered by grepping around in the source of the Mason page that\n" | |
| . "we just rendered, or the components that it used\n" | |
| . "\n" | |
| . "Both the symbol that's being clobbered and the symbol that\n" | |
| . "clobbered it represent a bug that we should fix, by either\n" | |
| . "renaming the subs so that their names don't collide, or better\n" | |
| . "yet just don't import them into the HTML::Mason::Commands\n" | |
| . "namespace in the first place."; | |
| } | |
| # Record the current symbols so the next request can | |
| # potentially whine about them. | |
| $MASON_SUBS_AT_REQUEST_START = copy_of_code_symbols(\%HTML::Mason::Commands::); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment