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

Catching SIGFPE #19081

Closed
hvds opened this issue Aug 24, 2021 · 7 comments
Closed

Catching SIGFPE #19081

hvds opened this issue Aug 24, 2021 · 7 comments

Comments

@hvds
Copy link
Contributor

hvds commented Aug 24, 2021

I don't know if it's possible to trigger in pure perl, but it is possible to get division by zero in external libraries, eg:

% ./perl -MMath::GMP -wle '$z = Math::GMP->new(1); print $z/0'
Floating point exception (core dumped)
% 

I thought it might be possible to catch that so as to use die or confess to get more information about the error, but that doesn't appear to work:

% $PERL -MMath::GMP -wle '$z = Math::GMP->new(1); $SIG{"FPE"} = sub { warn "divide by zero" }; print $z/0'
Maximal count of pending signals (120) exceeded at -e line 1.
% $PERL -MMath::GMP -wle '$z = Math::GMP->new(1); $SIG{"FPE"} = sub { die "divide by zero" }; print $z/0'
Maximal count of pending signals (120) exceeded at -e line 1.
% 

I assume this is because of perl's deferred signals logic, does anyone know of a way to get around that?

Failing that, is there a way to get a perl-level stack trace via gdb with a core dump?

Tested with recent blead:

Summary of my perl5 (revision 5 version 35 subversion 3) configuration:
  Derived from: a9475d1841f2673647c5ced6957dd637f9518979
  Platform:
    osname=linux
    osvers=5.4.0-73-generic
    archname=x86_64-linux
    uname='linux zen2 5.4.0-73-generic #82~18.04.1-ubuntu smp fri apr 16 15:10:02 utc 2021 x86_64 x86_64 x86_64 gnulinux '
    config_args='-des -Dcc=gcc -Dprefix=/opt/scratch -Doptimize=-g -O6 -Dusedevel -Uversiononly'
    hint=recommended
    useposix=true
    d_sigaction=define
    useithreads=undef
    usemultiplicity=undef
    use64bitint=define
    use64bitall=define
    uselongdouble=undef
    usemymalloc=n
    default_inc_excludes_dot=define
  Compiler:
    cc='gcc'
    ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
    optimize='-g -O6'
    cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
    ccversion=''
    gccversion='7.5.0'
    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='double'
    nvsize=8
    Off_t='off_t'
    lseeksize=8
    alignbytes=8
    prototype=define
  Linker and Libraries:
    ld='gcc'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib
    libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.27.so
    so=so
    useshrplib=false
    libperl=libperl.a
    gnulibc_version='2.27'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E'
    cccdlflags='-fPIC'
    lddlflags='-shared -g -O6 -L/usr/local/lib -fstack-protector-strong'


Characteristics of this binary (from libperl):
  Compile-time options:
    HAS_TIMES
    PERLIO_LAYERS
    PERL_COPY_ON_WRITE
    PERL_DONT_CREATE_GVSV
    PERL_MALLOC_WRAP
    PERL_OP_PARENT
    PERL_PRESERVE_IVUV
    PERL_USE_DEVEL
    USE_64_BIT_ALL
    USE_64_BIT_INT
    USE_LARGE_FILES
    USE_LOCALE
    USE_LOCALE_COLLATE
    USE_LOCALE_CTYPE
    USE_LOCALE_NUMERIC
    USE_LOCALE_TIME
    USE_PERLIO
    USE_PERL_ATOF
  Locally applied patches:
    uncommitted-changes
  Built under linux
  Compiled at Aug 16 2021 14:45:10
  %ENV:
    PERL="/opt/scratch/bin/perl"
  @INC:
    ../lib
    /opt/scratch/lib/perl5/site_perl/5.35.3/x86_64-linux
    /opt/scratch/lib/perl5/site_perl/5.35.3
    /opt/scratch/lib/perl5/5.35.3/x86_64-linux
    /opt/scratch/lib/perl5/5.35.3
    /opt/scratch/lib/perl5/site_perl
@Leont
Copy link
Contributor

Leont commented Aug 25, 2021

I assume this is because of perl's deferred signals logic

That is correct

does anyone know of a way to get around that?

$PERL -MPOSIX=sigaction,SIGFPE -MMath::GMP -wle '$z = Math::GMP->new(1); sigaction(SIGFPE, POSIX::SigAction->new(sub { die "divide by zero" })); print $z/0'

@hvds
Copy link
Contributor Author

hvds commented Aug 29, 2021

I assume this is because of perl's deferred signals logic

That is correct

does anyone know of a way to get around that?

$PERL -MPOSIX=sigaction,SIGFPE -MMath::GMP -wle '$z = Math::GMP->new(1); sigaction(SIGFPE, POSIX::SigAction->new(sub { die "divide by zero" })); print $z/0'

Thanks Leon; I've been looking more carefully through the docs (perlvar, perlipc, POSIX) to check if I should have been able to discover this myself, or to see if there is improvement possible there. While there is some discussion of deferred signals, I don't see anything much pointing me at the above solution. However I do find this, in perlipc:

    Signals as "faults"
        Certain signals like SEGV, ILL, and BUS are generated by virtual
        memory addressing errors and similar "faults". These are normally
        fatal: there is little a Perl-level handler can do with them. So Perl
        delivers them immediately rather than attempting to defer them.

.. which makes me wonder whether FPE should be classed as a "fault" in this sense, and if so whether Perl should be treating it the same way. If I understand the above paragraph correctly, such a change in Perl's handling of FPE would make it possible to catch it directly via %SIG.

@Leont
Copy link
Contributor

Leont commented Aug 29, 2021

which makes me wonder whether FPE should be classed as a "fault" in this sense, and if so whether Perl should be treating it the same way. If I understand the above paragraph correctly, such a change in Perl's handling of FPE would make it possible to catch it directly via %SIG.

That sounds reasonable to me, it really is a fault.

Though all of them should come with the explicit warning that such a handler should die.

@hvds
Copy link
Contributor Author

hvds commented Aug 31, 2021

which makes me wonder whether FPE should be classed as a "fault" in this sense, and if so whether Perl should be treating it the same way. If I understand the above paragraph correctly, such a change in Perl's handling of FPE would make it possible to catch it directly via %SIG.

That sounds reasonable to me, it really is a fault.

Though all of them should come with the explicit warning that such a handler should die.

I've created PR #19090 for this, including having a go at wording for such a warning.

Having said that, for some the preferred pattern might be more like:

use Carp;  # best have this loaded up front
$SIG{FPE} = sub {
  # get a stack trace for the error
  warn Carp::longmess("SIGFPE detected");
  # now let it rethrow to get a coredump
  $SIG{FPE} = 'DEFAULT';
  return;
};

@hvds
Copy link
Contributor Author

hvds commented Sep 8, 2021

#19090 was merged as 5892d8f, 49a2027 and 0ae3a5c, so closing this.

@hvds
Copy link
Contributor Author

hvds commented May 31, 2022

% $PERL -MMath::GMP -wle '$z = Math::GMP->new(1); $SIG{"FPE"} = sub { die "divide by zero" }; print $z/0'
Maximal count of pending signals (120) exceeded at -e line 1.

For the record, a PerlMonks question prompted me to discover that if the $SIG{FPE} is localized, we do see the die:

% perl-5.34.0 -MMath::GMP -wle '      $SIG{FPE} = sub { die "divide by zero" }; $z=Math::GMP->new(1); print $z / 0'
Maximal count of pending signals (120) exceeded at -e line 1.
% perl-5.34.0 -MMath::GMP -wle 'local $SIG{FPE} = sub { die "divide by zero" }; $z=Math::GMP->new(1); print $z / 0'
Maximal count of pending signals (120) exceeded at -e line 1.
divide by zero at -e line 1.
% 

That makes no sense to me - @Leont can you make sense of it? If there may be a bug here, I'll open a separate ticket.

@Leont
Copy link
Contributor

Leont commented Jun 1, 2022

For the record, a PerlMonks question prompted me to discover that if the $SIG{FPE} is localized, we do see the die:

I can't reproduce that. I think we're dealing with undefined behavior here.

If there may be a bug here, I'll open a separate ticket.

Given it only happens in an older release, I'm not sure that makes sense.

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