This is the mail archive of the libstdc++@sources.redhat.com mailing list for the libstdc++ project.


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

Re: gen-num-limits.cc & signal handling


   From: Gabriel Dos Reis <Gabriel.Dos-Reis@cmla.ens-cachan.fr>
   Date: 05 Dec 2000 03:42:55 +0100

   Mark Kettenis <kettenis@wins.uva.nl> writes:

   | ...  The behaviour of signal() is not entirely specified by
   | the relevant standards, and allows for SIGFPE to be blocked during the
   | execution of the signal handler, which happens for a BSD-like signal()
   | implementation.  The behaviour of longjmp() isn't entirely specified
   | either.  In particular, it doesn't have to restore the signal mask.

   Well in standard C, longjump() is required to restore the state of the
   executing environment saved by the most recent invocation of
   setjump().  Doesn't that cover the signal mask?

Unfortunately not.  My copy of the latest POSIX draft says:

   It is unspecified whether longjmp() restores the signal mask,
   leaves the signal mask unchanged, or restores it to its value at
   the time setjmp() was called.

and includes a warning about using longjmp() and setjmp() in
applications that depend on the value of the signal mask, telling
people to use siglongjmp() and sigsetjmp() instead.

   | However on the Hurd, generating a SIGFPE while it is being blocked
   | hangs the program.  And the #ifdef __CYGWIN__ suggests that cygwin
   | suffers from a similar problem.  The BeOS problems might be related
   | too.

   That is possible -- out of curiosity, I'm interested in knowing if
   that is actually what is happing on BeOS and Cygwin.

Me too :-).

   | Instead of special-casing these systems I'd like to propose to use
   | sigsetjmp/siglongjmp instead of setjmp/longjmp.  I've verified that
   | that works for the Hurd.  Since those functions might be absent on
   | non-POSIX systems, there should probably be an autoconf check for
   | those functions, and setjmp/longjmp could be used as a fall-back.

   Could you send a patch so that other port-maintainers can test?

Here it is.  If libstdc++-v3 is ever ported to a system that doesn't
have siglongjmp() and sigsetjmp() an autoconf check for those function
could, and the program could fall on longjmp() and setjmp() if they're
not available, as indicated by the comment I added.

I'd appreciate it if the Cygwin folks could test this.  I removed the
Cygwin specific code, but I'm not entirely sure whether using
siglongjmp() really makes all of the ripped out code obsolete.

Mark


2000-12-05  Mark Kettenis  <kettenis@gnu.org>

	* src/gen-num-limits.cc (env): Change type to sigjmp_buf.
	(signal_handler): Call siglongjmp instead of longjmp.
	[__CYGWIN__]: Remove specific code.
	(trapping): Call sigsetjmp instead of setjmp.


Index: libstdc++-v3/src/gen-num-limits.cc
===================================================================
RCS file: /cvs/gcc/egcs/libstdc++-v3/src/gen-num-limits.cc,v
retrieving revision 1.4
diff -u -p -r1.4 gen-num-limits.cc
--- libstdc++-v3/src/gen-num-limits.cc	2000/10/30 13:15:24	1.4
+++ libstdc++-v3/src/gen-num-limits.cc	2000/12/05 20:31:10
@@ -89,24 +89,42 @@ const int integer_base_rep = 2;
 // traps occur amounts -- for integer types -- to test whether traps
 // occur for int, unsigned, long, unsigned long. Furthermore
 // overflow cannot happen for unsigned integer types.
+//
+// Testing whether traps occur is done by installing a signal handler
+// for SIGFPE, and longjmp()-ing out of it.  However, the ISO C
+// standard grossly underspecifies signal() and setjmp()/longjmp(),
+// which results in a portability nightmare.  The ingredients are:
+//
+//   1. SIGFPE might or might not be blocked when executing the signal
+//   handler.
+//
+//   2. longjmp() might or might not restore the signal mask.
+//
+//   3. Raising a SIGFPE (i.e. dividing by zero or generating an
+//   overflow) while it is being blocked might invoke undefined
+//   behaviour (like generating a core dump, or spinning forever).
+//
+// Since ISO C doesn't say anything about signal masks and blocking of
+// signals, it is impossible to prevent bad things from happening by
+// only using ISO C functionality.  The code here uses
+// sigsetjmp()/siglongjmp() from POSIX to make sure the signal mask is
+// restored.  We should probably fall back on setjmp()/longjmp() on
+// systems that do not provide sigsetjmp() and siglongjmp(), and hope
+// for the best.  This isn't exactly hopeless since those systems are
+// likely not to have the concept of signal masks at all.  However
+// that isn't implemented yet.
 
-jmp_buf env;
+sigjmp_buf env;
 
 void signal_handler(int sig) 
 { 
-#ifdef __CYGWIN__
-  static sigset_t x;
-  signal (sig, signal_handler);
-  sigemptyset (&x);
-  sigprocmask(SIG_SETMASK, &x, NULL);
-#endif /* __CYGWIN__ */
-  longjmp(env, sig); 
+  siglongjmp(env, sig); 
 }
 
 template<typename Operation>
 bool trapping(const Operation& op)
 {
-    if (setjmp(env) == 0) op();
+    if (sigsetjmp(env, 1) == 0) op();
     else return true;
     return false;
 }



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