#1012073 perl: restoring default signal handler may warn with 'SIGTERM handler "DEFAULT" not defined'

Package:
perl
Source:
perl
Description:
Larry Wall's Practical Extraction and Report Language
Submitter:
Damyan Ivanov
Date:
2022-06-01 19:57:02 UTC
Severity:
normal
#1012073#5
Date:
2022-05-29 17:38:40 UTC
From:
To:
Control: block 923829 by -1

Hi,

While infestigating a random FTBFS in starlet (#923829), it appeared to me that
the problem is actually in perl. To reproduce te issue, t/12bad_request_line.t
needs to be run in a loop with the following change:

(starlet packaging repo is at
ssh://git@salsa.debian.org/perl-team/modules/packages/starlet.git)
-------------------------------------------
diff --git a/t/12bad_request_line.t b/t/12bad_request_line.t
index 61b4e7b..bdc8368 100644
--- a/t/12bad_request_line.t
+++ b/t/12bad_request_line.t
@@ -22,7 +22,7 @@ test_tcp(
         my $port = shift;
         local $SIG{__WARN__} = sub {
             ok 0, "No warnings";
-            diag @_;
+            diag Carp::longmess(@_);
         };
         my $loader = Plack::Loader->load('Starlet', port => $port);
         $loader->run(sub { [200, ['Content-Type' => 'text/plain'], ['OK']] });
-------------------------------------------

A sample loop is this:

 while prove -l t/12bad_request_line.t; do date; done

Running this simultaneously in several terminals may help triggering the
failure.

Eventually it fails with:

#   Failed test 'No warnings'
#   at t/12bad_request_line.t line 24.
# SIGTERM handler "DEFAULT" not defined.
#  at /usr/share/perl5/Parallel/Prefork.pm line 71.
# 	Parallel::Prefork::start(Parallel::Prefork=HASH(0x55cd856355b8)) called at .../lib/Plack/Handler/Starlet.pm line 78
# 	Plack::Handler::Starlet::run(Plack::Handler::Starlet=HASH(0x55cd849b0ad8), CODE(0x55cd8562ac98)) called at t/12bad_request_line.t line 28
# 	main::__ANON__(33415) called at /usr/share/perl5/Test/TCP.pm line 100
# 	Test::TCP::start(Test::TCP=HASH(0x55cd8562aed8)) called at /usr/share/perl5/Test/TCP.pm line 82
# 	Test::TCP::new("Test::TCP", "code", CODE(0x55cd8562aab8)) called at /usr/share/perl5/Test/TCP.pm line 28
# 	Test::TCP::test_tcp("client", CODE(0x55cd854306b0), "server", CODE(0x55cd8562aab8)) called at t/12bad_request_line.t line 31
# Looks like you failed 1 test of 2.
t/12bad_request_line.t .. Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/2 subtests

The lines in Parallel::Prefork where the warning comes from are:
https://salsa.debian.org/perl-team/modules/packages/libparallel-prefork-perl/-/blob/master/lib/Parallel/Prefork.pm#L71

     ...
     68             unless ($pid) {
     69                 # child process
     70                 $self->{in_child} = 1;
     71                 $SIG{$_} = 'DEFAULT' for keys %{$self->trap_signals};
     72                 $SIG{CHLD} = 'DEFAULT'; # revert to original
     73                 exit 0 if $self->signal_received;
     ...

Seems perfectly normal to me - signal handlers are reset in the forked child.

The only plausible source I find is line 3522 of mg.c:
https://salsa.debian.org/perl-team/interpreter/perl/-/blob/debian-5.34/mg.c#L3522

and here my idea of what is going on vanishes. I hope this is enough as a clue.

#1012073#12
Date:
2022-05-30 08:27:40 UTC
From:
To:
Just a quick reply that a smaller reproducer would obviously help.

FWIW this looks somewhat similar to

https://github.com/perl/perl5/issues/10913

but I assume the 'prefork' references mean threads are not involved
here. So perhaps unrelated after all.

#1012073#15
Date:
2022-06-01 19:46:44 UTC
From:
To:
-=| Niko Tyni, 30.05.2022 09:27:40 +0100 |=-

Yeah. Sorry about that. When I posted this I was already a bit tired
chasing where the warning comes from.

Here's a cleaner reproducer:

$ cat <<'EOF' > default-signal.pl
use strict;
use warnings;
use Carp::Always;   # to get a line number for the warning

$SIG{TERM} = sub{};
while() {
    my $pid = fork();
    defined($pid) or die 0;

    if ($pid) {
        sleep(0.1);
        kill TERM => $pid;
        wait;
    }
    else {
        $SIG{TERM} = "DEFAULT";
        exit(0);
    }
}
EOF

$ perl default-signal.pl
SIGTERM handler "DEFAULT" not defined.
 at default-signal.pl line 16.
…

On my laptop the warnings start to pour in a second or two.

If I comment out that sleep(), no warnings are shown.

This is what I looked at too and came to the same conclusion (threads
≠ forks).