diff --git a/lib/Mail/SpamAssassin.pm b/lib/Mail/SpamAssassin.pm index 472ba75a0c..0d3435a905 100644 --- a/lib/Mail/SpamAssassin.pm +++ b/lib/Mail/SpamAssassin.pm @@ -1661,6 +1661,25 @@ sub finish { $self->call_plugins("finish_tests", { conf => $self->{conf}, main => $self }); + # clean up eval-plugin glue (register_plugin_eval_glue()) and any + # plugin-registered generated rule methods (register_generated_rule_method()), + # left in place across all messages processed by this session -- see + # the comment in PerMsgStatus::finish() for why these aren't cleaned up + # per-message. register_plugin_eval_glue() pushes bare names (defined in + # the PerMsgStatus package); register_generated_rule_method() pushes + # fully-qualified ones -- qualify bare names here since, unlike + # PerMsgStatus::finish()'s original cleanup loop, this code doesn't run + # in the PerMsgStatus package itself. + { no strict 'refs'; + foreach my $method (@Mail::SpamAssassin::PerMsgStatus::TEMPORARY_METHODS) { + my $fqname = $method =~ /::/ ? $method + : "Mail::SpamAssassin::PerMsgStatus::$method"; + undef &{$fqname} if defined &{$fqname}; + } + } + @Mail::SpamAssassin::PerMsgStatus::TEMPORARY_METHODS = (); + %Mail::SpamAssassin::PerMsgStatus::TEMPORARY_EVAL_GLUE_METHODS = (); + $self->{plugins}->finish(); delete $self->{plugins}; if ($self->{bayes_scanner}) { diff --git a/lib/Mail/SpamAssassin/PerMsgStatus.pm b/lib/Mail/SpamAssassin/PerMsgStatus.pm index 5e561042e4..b08b763cc9 100644 --- a/lib/Mail/SpamAssassin/PerMsgStatus.pm +++ b/lib/Mail/SpamAssassin/PerMsgStatus.pm @@ -1959,14 +1959,14 @@ sub finish { $self->report_unsatisfied_actions(); - # Clean up temporary methods - foreach my $method (@TEMPORARY_METHODS) { - if (defined &{$method}) { - undef &{$method}; - } - } - @TEMPORARY_METHODS = (); # clear for next time - %TEMPORARY_EVAL_GLUE_METHODS = (); + # Note: @TEMPORARY_METHODS/%TEMPORARY_EVAL_GLUE_METHODS (eval-plugin glue + # generated by register_plugin_eval_glue(), and any methods a plugin + # registered via register_generated_rule_method()) are intentionally NOT + # cleaned up here. They're static per-config, safe to reuse for every + # message scanned by this process -- same lifetime as Check.pm's own + # compiled rule subs. Cleaning them up per-message forced eval-plugin + # glue to be eval()-recompiled on every single message. They're cleaned + # up once at session end, in Mail::SpamAssassin::finish(). # Delete out all of the members of $self. This will remove any direct # circular references and let the memory get reclaimed while also being more