svn commit: r1936486 - in spamassassin/trunk/lib/Mail: . SpamAssassin

[email protected] Wed, 22 Jul 2026 13:34:40 -0000
Newsgroups gmane.mail.spam.spamassassin.cvs
Message-ID <178472728042.606084.12579879836070642654@svn03-he-fi>
Author: gbechis
Date: Wed Jul 22 13:34:40 2026
New Revision: 1936486

Log:
Cache eval-plugin glue methods for the process lifetime, not per message

PerMsgStatus::finish() undefined every register_plugin_eval_glue()
generated wrapper sub (and any register_generated_rule_method() plugin
subs) and cleared their tracking hash after every single message, even
though this glue is 100% static per-config -- forcing a fresh eval()
compile of every distinct eval-plugin function on every message instead
of once per process, the same \"compile once, reuse\" pattern Check.pm
already uses for its rule subs.
It also contradicted register_generated_rule_method()'s
documented contract, which says these methods are destroyed at
Mail::SpamAssassin::finish() (session end), not per-message.

Move the cleanup to Mail::SpamAssassin::finish(), alongside the
existing finish_tests plugin-hook cleanup. Since that code runs
outside the PerMsgStatus package, bare (non-fully-qualified) method
names now need explicit qualification to avoid undefining the wrong
symbol.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

Submitted by: Giovanni <[email protected]>

Github: closes #34

Modified:
   spamassassin/trunk/lib/Mail/SpamAssassin.pm
   spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm

Modified: spamassassin/trunk/lib/Mail/SpamAssassin.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin.pm	Wed Jul 22 13:00:29 2026	(r1936485)
+++ spamassassin/trunk/lib/Mail/SpamAssassin.pm	Wed Jul 22 13:34:40 2026	(r1936486)
@@ -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}) {

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm	Wed Jul 22 13:00:29 2026	(r1936485)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm	Wed Jul 22 13:34:40 2026	(r1936486)
@@ -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