NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/57950: ucontext should provide accessors for fenv(3)



>Number:         57950
>Category:       lib
>Synopsis:       ucontext should provide accessors for fenv(3)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Feb 19 23:15:00 +0000 2024
>Originator:     Taylor R Campbell
>Release:        current, 10, 9, ...
>Organization:
Regents of the Ucontext of Califpudna
>Environment:
>Description:
When floating-point exception trapping is enabled with feenableexcept(3), and the system delivers SIGFPE on a floating-point exception trap, the system disables traps and clears sticky exceptions on entry to the signal handler.

The information of which exception traps were enabled, and which sticky exception bits were set, is lost in this case in any MI API -- except for the one exception that triggered this particular trap, which is reported through siginfo si_code.

However, the information is available through MD ucontext bits.  For example, on x86, ((struct fxsave *)ucp->uc_mcontext.__fpregs)->fx_cw, ->fx_sw, and ->fx_mxcsr have this information.  And the set of exceptions with sticky bits set or trapping enabled can also be controlled by writing to the ucontext before the signal handler returns; this way, the signal handler can, for example, record diagnostic information about where the first exception happened, and then let the program pick up where it left off but with exception trapping disabled.

It would be nice if there were an MI analogue of the fenv(3) API functions -- like fetestexcept to query sticky bits, feclearexcept/feraiseexcept to set sticky bits, fegetexcept to query exception trapping, and feenableexcept/fedisableexcept to control exception trapping -- that operated on a ucontext for use by a SIGFPE handler.  We have _UC_MACHINE_SP, _UC_MACHINE_PC, and similar MI functions -- it shouldn't be too hard (beyond a SMOP to do it on all architectures) to create a similar API for ucontext fenv(3) access.
>How-To-Repeat:
Try to adapt this example program to MI APIs:

#include <sys/ucontext.h>

#include <err.h>
#include <fenv.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>

#include <x86/cpu_extended_state.h>

void
on_sigfpe(int signo, siginfo_t *si, void *ctx)
{
	ucontext_t *ucp = ctx;
	struct fxsave *fx = (struct fxsave *)ucp->uc_mcontext.__fpregs;

	fprintf(stderr, "SIGFPE code=%d\n", si->si_code);
	fx->fx_cw |= FE_ALL_EXCEPT; /* mask all exception traps */
	fx->fx_mxcsr |= __SHIFTIN(FE_ALL_EXCEPT, __BITS(7,12));
	/* retry with exception traps masked */
}

volatile double one = 1;
volatile double zero = 0;
volatile double quot;

double
fpe_divbyzero(void)
{
	return one/zero;
}

int
main(void)
{
	struct sigaction sa;

	memset(&sa, 0, sizeof(sa));
	sa.sa_sigaction = &on_sigfpe;
	sigfillset(&sa.sa_mask);
	sa.sa_flags = SA_SIGINFO;
	if (sigaction(SIGFPE, &sa, NULL) == -1)
		err(1, "sigaction(SIGFPE)");

	feclearexcept(FE_ALL_EXCEPT);
	feenableexcept(FE_ALL_EXCEPT);
	fprintf(stderr, "dividing by zero 1, trap=0x%x\n", fegetexcept());
	fprintf(stderr, "result=%a\n", fpe_divbyzero());
	fprintf(stderr, "dividing by zero 2, trap=0x%x\n", fegetexcept());
	fprintf(stderr, "result=%a\n", fpe_divbyzero());

	return 0;
}

>Fix:
Yes, please!



Home | Main Index | Thread Index | Old Index