FPSCR and 64-bit signal handlers

Gary Byers gb at clozure.com
Sun Nov 13 19:06:45 EST 2005


Hi.

In the 2.6.14 kernel.org tree, the function setup_sigcontext()
(in .../arch/ppc64/signal.c) contains (inter alia):


 	flush_fp_to_thread(current);

 	/* Make sure signal doesn't get spurrious FP exceptions */
 	current->thread.fpscr = 0;

 	[...]
 	err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
         [...]

There seem to be a couple of unfortunate consequences of these things
happening in this order:

1) The FPSCR image in current->thread.fpscr is zeroed before the thread's
FP context is copied out to the userspace sigcontext; this means that
the handler will run with the FPSCR set to 0 (which is arguably good),
but it also means that the handler does not have access to the FPSCR
value at the time of the exception.  This also means that - unless all
signal handlers are aware of this issue and somehow work around it -
a thread's FPSCR value may be changed from non-zero to zero on return
from a handler from any signal handler whose context was established
by this function.

(I'd think that changing the order in which the copyout and the zeroing
of the FPSCR occur would fix this.)

2) The assembly-language function flush_fp_to_thread() has a
side-effect on the f0/fr0 register (it's used to access the value of
the FPSCR and store it in the thread context after it and the other 31
fp registers have been saved there.)  There seem to be execution paths
in which flush_fp_to_thread() is called at least once between the time
that an exception is detected and the call above in setup_sigcontext()
(it's called in parse_fpe(), in .../arch/ppc64/traps.c); on any call
other than the first, the value of f0/fr0 saved in the current thread
context will be incorrect (it'll contain some of the bits that were in
the FPSCR on the most recent previous call.)  This means both that
signal handlers that care about the value of f0/fr0 will get incorrect
information and also that the value of f0/fr0 can change unexpectedly
on return from any signal handler whose context was established by
this function if there was more than one call to flush_fp_to_thread()
on the execution path.

(I'd guess that the best fix would be to have flush_fp_to_thread()
be a little more careful about preserving the value of f0/fr0, perhaps
by reloading it after it'd been used to access and save the FPSCR.)

I don't know how many programs are affected by these problems, but
as I understand them these are both serious problems.

Gary Byers
gb at clozure.com
http://www.clozure.com



More information about the Linuxppc64-dev mailing list