NetBSD-Bugs archive

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

port-i386/39299: FPU use in signal handlers is unsafe

>Number:         39299
>Category:       port-i386
>Synopsis:       FPU use in signal handlers is unsafe
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Aug 06 14:35:00 +0000 2008
>Originator:     Matthias Drochner
>Release:        current
NetBSD zelz27 4.99.72 NetBSD 4.99.72 (MIST+MP) #93: Wed Aug  6 15:54:47 MEST 

When a signal handler is called, the FPU is in the state as the
main program left it. In particular, there can be data on the
stack which causes that the stack overflows early.

Start the appended program and send SIGUSR1 to it.
(The calculation in the signal handler is just a test which is
easy but cannot be optimized away by the compiler. The "fld1"
in the main program fills up the FPU stack.)

#include <stdio.h>
#include <math.h>
#include <signal.h>

#define IV 0.739085
double a = IV;

static void
sh(int s, siginfo_t *i, void *ctx)
        double a1;

        a1 = cos(a);
        if (isnan(a1) || fabs(a - a1) > 0.0001) {
                fprintf(stderr, "%g/%g (sh)\n", a, a1);
                a1 = IV;
        a = a1;

        struct sigaction sa;
        int i;

        sa.sa_sigaction = sh;
        sa.sa_flags = SA_SIGINFO;
        sigaction(SIGUSR1, &sa, 0);

        for (i = 0; i < 8; i++)

        for (;;);

The appended patch fixes the issue for me. It should be possiple
to do it better, so that just the TS bit gets set but no fpu save
is done unless the signal handler tries to use it.

--- sys/arch/i386/i386/machdep.c
+++ sys/arch/i386/i386/machdep.c
@@ -833,6 +833,10 @@ sendsig_siginfo(const ksiginfo_t *ksi, c

        buildcontext(l, sel, catcher, fp);

+       /* make sure we get a clean FPU */
+       npxsave_lwp(l, 0);
+       l->l_md.md_flags &= ~MDL_USEDFPU;
        /* Remember that we're now on the signal stack. */
        if (onstack)
                l->l_sigstk.ss_flags |= SS_ONSTACK;

Home | Main Index | Thread Index | Old Index