Description
Module: POSIX
Perl POSIX::SigSet/SigAction can cause Perl to hang or core dump with a memory fault.
I've reproduced this issue with 5.36 and 5.38 using RedHat Linux 7.9 and 9.0, but in both cases I compiled Perl, aka I was not using the OS Perl.
The issue occurs when handling a SIGHUP. It generally takes many attempts (sometimes thousands) of handled SIGHUPs before the issue occurs.
When it hangs, an strike shows it hanging on a FUTEX call:
strace -p 256070
strace: Process 256070 attached
futex(0x7f92c3c59760, FUTEX_WAIT_PRIVATE, 2, NULL
^C strace: Process 256070 detached
If I force a core dump of this, the stack trace shows:
(gdb) where
#0 0x00007fc1be1067fc in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x00007fc1be082ca7 in _L_lock_18166 () from /lib64/libc.so.6
#2 0x00007fc1be0801d9 in calloc () from /lib64/libc.so.6
#3 0x00000000004e58d6 in Perl_safesyscalloc ()
#4 0x0000000000506449 in Perl_hv_common ()
#5 0x000000000050739e in Perl_hv_common_key_len ()
#6 0x00000000004f3595 in Perl_perly_sighandler ()
#7 <signal handler called>
#8 0x00007fc1be07b013 in _int_free () from /lib64/libc.so.6
#9 0x000000000051c3c2 in Perl_sv_clear ()
#10 0x000000000051c631 in Perl_sv_free2 ()
#11 0x000000000054e8de in Perl_free_tmps ()
#12 0x000000000050c818 in Perl_pp_unstack ()
#13 0x000000000050bbd6 in Perl_runops_standard ()
#14 0x0000000000440586 in perl_run ()
#15 0x0000000000417b89 in main ()
Replacing POSIX::Sig* with a simple $SIG{HUP} handler does not behave this way.
If I really push the HUPs (no sleep between each HUP) I can trigger it to crash and core dump. The core file show the following stack trace:
warning: Signature not supported. Hash algorithm SHA1 not available.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `/usr/local/bin/perl ./sigtest.pl'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000000000052021c in Perl_sv_upgrade ()
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.34-60.el9.x86_64 libxcrypt-4.4.18-3.el9.x86_64
(gdb) where
#0 0x000000000052021c in Perl_sv_upgrade ()
#1 0x000000000051ef4b in Perl_sv_setsv_flags ()
#2 0x000000000052c79a in Perl_newSVsv_flags ()
#3 0x00000000004ee317 in Perl_perly_sighandler ()
#4 <signal handler called>
#5 0x00007efbffaaf922 in free () from /lib64/libc.so.6
#6 0x0000000000515ae4 in Perl_sv_clear ()
#7 0x0000000000515d6e in Perl_sv_free2 ()
#8 0x0000000000549477 in Perl_free_tmps ()
#9 0x0000000000507cf8 in Perl_pp_unstack ()
#10 0x00000000005064a6 in Perl_runops_standard ()
#11 0x000000000043f55c in perl_run ()
#12 0x0000000000416552 in main ()
Steps to Reproduce
This can be reproduced using this script, it can take few minutes to hang. I suspect it just depends on where in the code it is when the HUP arrives.
#!/usr/local/bin/perl
use strict;
use Time::HiRes;
use POSIX;
print "PPID : $$\n";
my $ppid = $$;
for my $i ((0..2))
{
my $pid = fork();
unless ($pid)
{
sleep 1;
while (1)
{
kill 'HUP',$ppid;
Time::HiRes::sleep(.001);
}
exit;
}
print "child $pid\n";
}
my $sh = POSIX::SigSet->new();
my $old = {};
$sh->addset(SIGHUP);
my $cnt = 0;
$|=1;
my $action = POSIX::SigAction->new(sub {
my ($signal,$source) = @_;
$cnt++;
my $back = "\b" x length($cnt);
print $back.$cnt;
},$sh,&SA_SIGINFO);
sigaction(SIGHUP,$action,$old);
while(1)
{
sleep 1;
}
Expected behavior
This code should never hang in this fashion.
Perl configuration
Summary of my perl5 (revision 5 version 38 subversion 0) configuration:
Platform:
osname=linux
osvers=3.10.0-1160.90.1.el7.x86_64
archname=x86_64-linux-thread-multi-ld
uname='linux kennel445 3.10.0-1160.90.1.el7.x86_64 #1 smp fri mar 17 08:39:44 utc 2023 x86_64 x86_64 x86_64 gnulinux '
config_args='-Accflags=-DNO_POSIX_2008_LOCALE -Dusesitecustomize -Dusethreads -Ud_flock -Dusemorebits -Accflags=-fPIC -D_FORTIFY_SOURCE=2 -d'
hint=recommended
useposix=true
d_sigaction=define
useithreads=define
usemultiplicity=define
use64bitint=define
use64bitall=define
uselongdouble=define
usemymalloc=n
default_inc_excludes_dot=define
Compiler:
cc='cc'
ccflags ='-std=gnu99 -D_REENTRANT -D_GNU_SOURCE -DNO_POSIX_2008_LOCALE -fPIC -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2'
optimize='-O2'
cppflags='-std=gnu99 -D_REENTRANT -D_GNU_SOURCE -DNO_POSIX_2008_LOCALE -fPIC -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
ccversion=''
gccversion='4.8.5 20150623 (Red Hat 4.8.5-44)'
gccosandvers=''
intsize=4
longsize=8
ptrsize=8
doublesize=8
byteorder=12345678
doublekind=3
d_longlong=define
longlongsize=8
d_longdbl=define
longdblsize=16
longdblkind=3
ivtype='long'
ivsize=8
nvtype='long double'
nvsize=16
Off_t='off_t'
lseeksize=8
alignbytes=16
prototype=define
Linker and Libraries:
ld='cc'
ldflags =' -fstack-protector-strong -L/usr/local/lib'
libpth=/usr/local/lib /usr/lib /usr/lib64 /usr/local/lib64
libs=-lpthread -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
perllibs=-lpthread -ldl -lm -lcrypt -lutil -lc
libc=libc-2.17.so
so=so
useshrplib=false
libperl=libperl.a
gnulibc_version='2.17'
Dynamic Linking:
dlsrc=dl_dlopen.xs
dlext=so
d_dlsymun=undef
ccdlflags='-Wl,-E'
cccdlflags='-fPIC'
lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'
Characteristics of this binary (from libperl):
Compile-time options:
HAS_LONG_DOUBLE
HAS_STRTOLD
HAS_TIMES
MULTIPLICITY
PERLIO_LAYERS
PERL_COPY_ON_WRITE
PERL_DONT_CREATE_GVSV
PERL_HASH_FUNC_SIPHASH13
PERL_HASH_USE_SBOX32
PERL_MALLOC_WRAP
PERL_OP_PARENT
PERL_PRESERVE_IVUV
PERL_USE_SAFE_PUTENV
USE_64_BIT_ALL
USE_64_BIT_INT
USE_ITHREADS
USE_LARGE_FILES
USE_LOCALE
USE_LOCALE_COLLATE
USE_LOCALE_CTYPE
USE_LOCALE_NUMERIC
USE_LOCALE_TIME
USE_LONG_DOUBLE
USE_PERLIO
USE_PERL_ATOF
USE_REENTRANT_API
USE_SITECUSTOMIZE
Built under linux
Compiled at Jul 28 2023 11:23:45
%ENV:
PERL5LIB="/home/dfreed/perl526/lib/perl/arch:/home/dfreed/perl526/lib/perl"
@INC:
/home/dfreed/perl526/lib/perl/arch
/home/dfreed/perl526/lib/perl
/usr/local/lib/perl5/site_perl/5.38.0/x86_64-linux-thread-multi-ld
/usr/local/lib/perl5/site_perl/5.38.0
/usr/local/lib/perl5/5.38.0/x86_64-linux-thread-multi-ld
/usr/local/lib/perl5/5.38.0
FYI /home/dfreed/perl526/ doesn't exist, so it isn't anything there that is affecting this behavior.