This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[Hakon.Bugge@scali.com] libc/1739: signal+siglongjmp destroys FP control word on x86



Hi glibc folks,

We've received the appended bug report about signal/siglongjmp.

Hakon is right, we don't save anything at all about the FPU.

Looking at the description of setjmp in ISO C 1999, I found:

       The environment of a call to the setjmp macro consists of
       information sufficient for a call to the longjmp function to
       return execution to the correct block and invocation of that
       block, were it called recursively.  It does not include the
       state of the floating-point status flags, of open files, or of
       any other component of the abstract machine.

Since siglongjmp is an extension of setjmp/longjmp only with respect
to signal handling, it seems that I can close the bug report with the
comment "You're right - but we're following the ISO C standard which
explictly forbids this".

What do you think?

Andreas


Subject: Topics

Topics:
   libc/1739: signal+siglongjmp destroys FP control word on x86




>Number:         1739
>Category:       libc
>Synopsis:       signal+siglongjmp destroys FP control word on x86
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    libc-gnats
>State:          open
>Class:          sw-bug
>Submitter-Id:   unknown
>Arrival-Date:   Mon May 15 10:00:03 EDT 2000
>Last-Modified:
>Originator:     Hakon.Bugge@scali.com
>Organization:
net
>Release:        2.1.x
>Environment:
linux 2.2.x (i.e. RH 6.x) on x86.
>Description:
A (sig)setjmp()+(sig)longjmp() does not save/restore FPU control word.
Compilers have switches for controlling the precision mode (e.g. pgicc).
If the aplication performs a (sig)longjmp() from a signal handler,
the correct FPU control word is not restored, and the program continues
execution using a different precision. Since the FPU control word cannot
be considered as "... non-volatile automatic variables in the function
calling setjmp ..." to use the ANSI C parlance, this must in my opinion
be considered a bug.

As a reference, the enclosed program work unser Solaris/x86.

A pthread application being (pthread) signalled while waiting in a
pthread_cond_timedwait() is exposed to this bug (sample program available
upon request).

This bug is very annoying if the application requires 64-bit FP precision
and is exposed to the bug, e.g., uses pthreads.

Below is a sample program demonstrating the bug.



Enjoy!

hob

---------------------------------
/*
 * Author: H. Bugge, Scali AS, May 2000
 *  
 * This program demonstrates that the Linux/x86 signal system invokes
 * the signal catching routine with an incorrect FP control word.
 * This is extreemly annoying if 64-bit precision is required, and the
 * application uses signals, e.g. pthreads.
 *
 * To compile&run:
 *
 *     gcc fpucw.c;a.out
 */


#include <assert.h>
#include <fpu_control.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

typedef void (*sighandler_t)(int);
jmp_buf env;
char *precision_mnemonic[] = {"SINGLE", "BAD VALUE", "DOUBLE", "EXTENDED" };

void print_fp_precision(char *str, int expected_prec) {
  int actual_prec;
  fpu_control_t cw;
  
  _FPU_GETCW(cw);
  actual_prec = cw & _FPU_EXTENDED;
  printf("%-20s: %10s. %s\n",
	str, precision_mnemonic[actual_prec >> 8],
	(actual_prec == expected_prec ? "OK" : "ERROR")
);
}


sighandler_t catcher(int sig) {

  print_fp_precision("Before siglongjmp", _FPU_DOUBLE);
  siglongjmp(env, 1);
}


int main() {
   fpu_control_t cw;


  print_fp_precision("Beginning of main()", _FPU_EXTENDED);

  /* set 64-bit FP precision */
  _FPU_GETCW(cw);
  cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
  _FPU_SETCW(cw);
  print_fp_precision("After _FP_SETCW", _FPU_DOUBLE);

  signal(SIGUSR2, (sighandler_t)catcher);

  print_fp_precision("Before sigsetjmp", _FPU_DOUBLE);
  if (sigsetjmp(env, 1) == 0) {
    print_fp_precision("After sigsetjmp", _FPU_DOUBLE);
    kill(getpid(), SIGUSR2);
    assert(0);
  } else {
    print_fp_precision("After longjmp", _FPU_DOUBLE);
  }
  
  return(0);
}    


>How-To-Repeat:
gcc fpucw.c; a.ou
>Fix:
>Audit-Trail:
>Unformatted:





-- 
 Andreas Jaeger
  SuSE Labs aj@suse.de
   private aj@arthur.inka.de


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]