It seems that on the M1, MacOS does not send a SIGFPE, but rather a SIGILL, when floating point exceptions are unblocked. Here is a version of the code above that will work.
I've also included a call to sigaction and a second handler to query the signal code that is sent.
#include <fenv.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void fpe_signal_handler(int sig)
{
printf("Floating point exception\n");
int i = fetestexcept(FE_INVALID);
if (i & FE_INVALID)
printf("----> Invalid valued detected\n");
exit(1);
}
static void
fpe_signal_action( int sig, siginfo_t *sip, void *scp )
{
/* see signal.h for codes */
int fe_code = sip->si_code;
if (fe_code == ILL_ILLTRP)
printf("Illegal trap detected\n");
else
printf("Code detected : %d\n",fe_code);
int i = fetestexcept(FE_INVALID);
if (i & FE_INVALID)
printf("---> Invalid valued detected\n");
abort();
}
void enable_floating_point_exceptions()
{
fenv_t env;
fegetenv(&env);
env.__fpcr = env.__fpcr | __fpcr_trap_invalid;
fesetenv(&env);
#if 1
signal(SIGILL,fpe_signal_handler);
#else
struct sigaction act;
act.sa_sigaction = fpe_signal_action;
sigemptyset (&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGILL, &act, NULL);
#endif
}
void main()
{
const double x = -1;
printf("y = %f\n",sqrt(x));
enable_floating_point_exceptions();
printf("y = %f\n",sqrt(x));
}
I compiled this as:
gcc -o fpe fpe.c
and the output is:
y = nan
Floating point exception
----> Invalid valued detected
The good news is that only exceptions that are unmasked will be handled. If an exception remains masked, the code terminates normally. Also, it does not seem to be an issue with the M1, but rather with MacOS (Monterey 12.3.1, in my case) on the M1. On a Linux VM (on Apple silicon), the SIGFPE works as expected.
One question I have is how reliable fetestexcept is in this case. Can it be relied upon to determine the exception that was caught when used in the signal handler? Or is it better to use codes sent by SIGFPE (when available) and detect FPE_FLTINV, FPE_FLTDIV and so on?
Related StackOverflow posts :
How to trap floating-point exceptions on M1 Macs
Trapping floating point exceptions and signal handling on Apple silicon