Package: spamassassin / 3.3.2-5+deb7u3

95_bug694504-spamdforkscaling-crash Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
Index: spamassassin-3.3.2/lib/Mail/SpamAssassin/Logger/Syslog.pm
===================================================================
--- spamassassin-3.3.2.orig/lib/Mail/SpamAssassin/Logger/Syslog.pm	2013-01-22 20:19:12.000000000 -0800
+++ spamassassin-3.3.2/lib/Mail/SpamAssassin/Logger/Syslog.pm	2013-01-22 20:19:57.000000000 -0800
@@ -148,17 +148,21 @@
   }
   $msg = $timestamp . ' ' . $msg  if $timestamp ne '';
 
-  # important: do not call syslog() from the SIGCHLD handler
-  # child_handler().   otherwise we can get into a loop if syslog()
-  # forks a process -- as it does in syslog-ng apparently! (bug 3625)
-  $Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER} = 1;
+# no longer needed since a patch to bug 6745:
+# # important: do not call syslog() from the SIGCHLD handler
+# # child_handler().   otherwise we can get into a loop if syslog()
+# # forks a process -- as it does in syslog-ng apparently! (bug 3625)
+# $Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER} = 1;
+
   my $eval_stat;
   eval {
     syslog($level, "%s", $msg); 1;
   } or do {
     $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;
   };
-  $Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER} = 0;
+
+# no longer needed since a patch to bug 6745:
+# $Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER} = 0;
 
   if (defined $eval_stat) {
     if ($self->check_syslog_sigpipe($msg)) {
Index: spamassassin-3.3.2/spamd/spamd.raw
===================================================================
--- spamassassin-3.3.2.orig/spamd/spamd.raw	2013-01-22 20:19:12.000000000 -0800
+++ spamassassin-3.3.2/spamd/spamd.raw	2013-01-22 20:19:57.000000000 -0800
@@ -588,6 +588,7 @@
 my $timeout_child;        # processing timeout (headers->finish), 0=no timeout
 my $clients_per_child;    # number of clients each child should process
 my %children;             # current children
+my @children_exited;
 
 if ( defined $opt{'max-children'} ) {
   $childlimit = $opt{'max-children'};
@@ -1031,6 +1032,8 @@
 # child_handler()  if !$scaling || am_running_on_windows();
   child_handler();  # it doesn't hurt to call child_handler unconditionally
 
+  child_cleaner();
+
   do_sighup_restart()  if defined $got_sighup;
 
   for (my $i = keys %children; $i < $childlimit; $i++) {
@@ -2517,7 +2520,8 @@
   my ($sig) = @_;
 
   # do NOT call syslog here unless the child's pid is in our list of known
-  # children.  This is due to syslog-ng brokenness -- bugs 3625, 4237.
+  # children.  This is due to syslog-ng brokenness -- bugs 3625, 4237;
+  # see also bug 6745.
 
   # clean up any children which have exited
   for (;;) {
@@ -2528,12 +2532,23 @@
     #
     my $pid = waitpid(-1, WNOHANG);
     last if !$pid || $pid == -1;
-    my $child_stat = $?;
+    push(@children_exited, [$pid, $?, $sig, time]);
+  }
 
-    if (!defined $children{$pid}) {
-      # ignore this child; we didn't realise we'd forked it. bug 4237
-      next;
-    }
+  $SIG{CHLD} = \&child_handler;    # reset as necessary, should be at end
+}
+
+# takes care of dead children, as noted by a child_handler()
+# called in a main program flow (not from a signal handler)
+#
+sub child_cleaner {
+  while (@children_exited) {
+    my $tuple = shift(@children_exited);
+    next if !$tuple;  # just in case
+    my($pid, $child_stat, $sig, $timestamp) = @$tuple;
+
+    # ignore this child if we didn't realise we'd forked it. bug 4237
+    next if !defined $children{$pid};
 
     # remove them from our child listing
     delete $children{$pid};
@@ -2544,15 +2559,10 @@
       my $sock = $backchannel->get_socket_for_child($pid);
       if ($sock) { $sock->close(); }
     }
-
-    unless ($Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER}) {
-      info("spamd: handled cleanup of child pid [%s]%s: %s",
-           $pid, (defined $sig ? " due to SIG$sig" : ""),
-           exit_status_str($child_stat,0));
-    }
+    info("spamd: handled cleanup of child pid [%s]%s: %s",
+         $pid, (defined $sig ? " due to SIG$sig" : ""),
+         exit_status_str($child_stat,0));
   }
-
-  $SIG{CHLD} = \&child_handler;    # reset as necessary, should be at end
 }
 
 sub restart_handler {