Dieser Post wurde aus meiner alten WordPress-Installation importiert. Sollte es Darstellungsprobleme, falsche Links oder fehlende Bilder geben, bitte einfach hier einen Kommentar hinterlassen. Danke.
I joined a commercial project lately which has been growing for years. Adding a "use" for a module which was called in source but not loaded by "use" before suddenly led some old coding sins show up. Torben and I spent two hours on finding and fixing this bug. The project serves many similar scops with common source for all scopes and individual source for each scope. A long time ago
foreach my $module (@modules) { my $modfile = $scope . "/" . $module . ".pm";
require $modfile;
my $origmodname = $scope . '::' . $module . '::'; my $modname = $module . '::';
for my $function (keys %{$origmodname}) { ${$modname}{$function} = ${$origmodname}{$function}; }}I don't want to judge this source, it was written before I was here and it was working all the time, but we're planning to replace it by a completely new concept in the future. Back to the error: Some newer scripts run without any scope and some of them even fail when modules are mapped as shown above. A new sub was added to clean up the virtual namespaces at every script start:
foreach my $module (@modules) { my $modname = $module . '::'; for my $fn (keys %{$modname}) { ${$modname}{$fn} = "*dontdefineme"; }}Everything mapped earlier is being cleared by setting it to "*dontdefineme", which looks like a GLOB reference, but isn't one, it's a simple scalar string. Some cronjobs walk through all scopes and remap the virtual namespaces to each individual scope after running the cleanup sub before. One of them - a very important one - started crashing yesterday just after my added "use" statements went online. What happend? Step-by-step debugging the source tracked down the crash to the "require" statement from the first snippet. It started walking through the modules processing each "use" statement and suddenly failed after processing a "use Date::Calc". The popular date manipulation module wasn't responsible for the crash, a compilation error occurred just after it had been loaded successfully.
Not enough arguments for Module::foo at SomeModule.pm line 123, near "()"The error doesn't mean what it looks like, the called function - called from within an eval block - didn't require any argument and didn't use prototypingat all. No other file within all scopes and common source defined this sub with prototypes. What happend? The error message is wrong, it seems to be a little compiler bug but usually not a critical one, because mixing up a namespace's symbol table is strongly not recommended. Doing so may lead to unexpected errors - like it did in this case. The module in question had an eval { } block (which is compiled at compile time) calling the sub which was reported to have too few arguments. The problem didn't pop up when calling those subs outside of eval { } and it didn't happen when changing the eval block to string eval using ' instead of the block brackets. I assume that Perl was checking the symbol table for the sub in question. It didn't contain a valid blob reference and the compiler wasn't able to handle this unexpected case. We created a simple empty sub and used it for cleaning up the virtual namespace:
sub dontuseme {
}
[...]
${$modname}{$fn} = $MappingModule::{dontuseme};Everything is working now. I don't want to write "everything is fine", because it isn't. Torben and I decided to increase the priority of removing this piece of code - but we've to provide a solution for all other teams currently using the virtual namespace and every script has to be converted before we could remove these modules.
Noch keine Kommentare. Schreib was dazu