[prev in list] [next in list] [prev in thread] [next in thread]
List: netbsd-tech-kern
Subject: Re: Expected behavior when returning from a SIGFPE handler
From: Jason Thorpe <thorpej () me ! com>
Date: 2021-05-27 16:14:31
Message-ID: 73EEE950-9FFF-43B0-8A32-30C358BA7525 () me ! com
[Download RAW message or body]
> On May 27, 2021, at 6:17 AM, Jason Thorpe <thorpej@me.com> wrote:
>
> >
> > On May 27, 2021, at 3:35 AM, Taylor R Campbell \
> > <campbell+netbsd-tech-kern@mumble.net> wrote:
> > > Date: Wed, 26 May 2021 19:46:57 -0700
> > > From: Jason Thorpe <thorpej@me.com>
> > >
> > > The test program sets up a SIGFPE handler, and the handler make a
> > > copy of the siginfo, sets a global flag, and returns. The program
> > > then does "1.0 / 0.0" and prints the result. It checks to ensure
> > > that the DZE exception is set via fpgetsticky(). It then does "1.0
> > > / 0.0" again, and then verifies that the SIGFPE handler was not
> > > called a second time (because I never cleared DZE with
> > > fpsetsticky()).
> >
> > This strikes me as wrong.
> >
> > The status flags (fpgetsticky, fetestexcept) don't determine whether a
> > floating-point operation `signals an exception' (in the language of
> > IEEE 754-2019); they only record whether it happened in the past.
> >
> > It seems to me that if an operation [ieee754-]signals an exception
> > that the user has asked (with fpsetmask/feenableexcept) to be trapped,
> > then it should deliver a [unix-]signal, irrespective of whether some
> > past operation already [ieee754-]signalled an exception.
>
> I agree. I was describing behavior the alpha port already had. I will write a \
> unit test for this behavior (specifically round DZE), or make sure that there is \
> one that covers it already (there may be … I'm still peeling the onion on the \
> alpha port…)
Ok, circling back on this point, the behavior I described for the alpha port is also \
how amd64 behaves, which is to say "if the an exception is enabled and the \
exception's flag is already set, then the signal handler will not be called on a \
second triggering of the exceptional condition".
Consider this test program:
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <ieeefp.h>
volatile float f_zero = 0.0;
siginfo_t siginfo_copy;
jmp_buf sigfpe_env;
volatile float f_result;
static void
sigfpe_action(int sig, siginfo_t *info, void *ctx)
{
siginfo_copy = *info;
longjmp(sigfpe_env, 1);
}
static void __noinline
divide_by_zero(void)
{
f_result = 1.0 / f_zero;
}
int
main(int argc, char *argv[])
{
struct sigaction sigact = {
.sa_sigaction = sigfpe_action,
.sa_flags = SA_SIGINFO,
};
(void) sigaction(SIGFPE, &sigact, NULL);
fp_except_t mask = fpgetmask();
printf("default MASK:\n");
if (mask & FP_X_INV)
printf("\tFP_X_INV\n");
if (mask & FP_X_DZ)
printf("\tFP_X_DZ\n");
if (mask & FP_X_OFL)
printf("\tFP_X_OFL\n");
if (mask & FP_X_UFL)
printf("\tFP_X_UFL\n");
if (mask & FP_X_IMP)
printf("\tFP_X_IMP\n");
#ifdef FP_X_IOV
if (mask & FP_X_IOV)
printf("\tFP_X_IOV\n");
#endif
fpsetmask(FP_X_DZ);
if (setjmp(sigfpe_env)) {
printf("SIGFPE 1 received: signo=%d code=%d\n",
siginfo_copy.si_signo,
siginfo_copy.si_code);
} else {
divide_by_zero();
printf("1: 1.0 / f_zero -> %f\n", f_result);
}
fp_except_t sticky = fpgetsticky();
if (sticky & FP_X_DZ) {
printf("1: GOT FP_X_DZ!\n");
}
if (setjmp(sigfpe_env)) {
printf("SIGFPE 2 received: signo=%d code=%d\n",
siginfo_copy.si_signo,
siginfo_copy.si_code);
} else {
divide_by_zero();
printf("2: 1.0 / f_zero -> %f\n", f_result);
}
sticky = fpgetsticky();
if (sticky & FP_X_DZ) {
printf("2: GOT FP_X_DZ!\n");
}
return 0;
}
Running this program on amd64 results in:
the-ripe-vessel:thorpej 50$ ./fptest
default MASK:
SIGFPE 1 received: signo=8 code=3
2: 1.0 / f_zero -> inf
2: GOT FP_X_DZ!
the-ripe-vessel:thorpej 51$
…which seems very counter-intuitive to me.
I enable FP_X_DZ, I get the SIGFPE signal the first time, and fpgetsticky() does NOT \
indicate FP_X_DZ … yet I do not get the second SIGFPE, and I get FP_X_DZ from the \
second call to fpgetsticky()?
WTF is going on here?
-- thorpej
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic