Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POSIX::SigSet / SigAction hang or core dump #21308

Closed
DanFreed opened this issue Jul 28, 2023 · 1 comment
Closed

POSIX::SigSet / SigAction hang or core dump #21308

DanFreed opened this issue Jul 28, 2023 · 1 comment

Comments

@DanFreed
Copy link

DanFreed commented Jul 28, 2023

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.

@Leont
Copy link
Contributor

Leont commented Jul 28, 2023

sigaction sets an unsafe signal handler by default. This can segfault under certain circumstances, that's why they're generally not recommended. This is not the fault of POSIX::SigSet or POSIX::SigAction. You may want to call $action->safe(1); to prevent this crash.

@Leont Leont closed this as completed Jul 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants