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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] libc/include/machine/setjmp.h: Only evaluate first parameter to sig{set,long}jmp once


Hi,

while debugging current CVS of GDB under Cygwin, I found that the cause
of the problem I was looking for was this (simplified for readability):

- There's a function call which returns a pointer to a freshly allocated
  sigjmp_buf, let's name it alloc_jmpbuf().

- sigsetjmp is called like this:

    sigsetjmp (*alloc_jmpbuf(), 1);

- In libc/include/machine/setjmp.h, sigsetjmp is defined like this:

    #define sigsetjmp(env, savemask) ((env)[_SAVEMASK] = savemask,\
	       sigprocmask (SIG_SETMASK, 0, (sigset_t *) ((env) + _SIGMASK)),\
	       setjmp (env))

A close look into this macro shows, that the first parameter, "env" is
evaluated three times.  In the above situation, that means that three
times the function alloc_jmpbuf() is invocated, therefore three new
sigjmp_buf's exist after one call to sigsetjmp.

While the implementation of sigsetjmp is not wrong in the first place,
it would be better if the implementation would handle cases like the
above gracefully.

Therefore I propose the below patch.  It uses a GCC extension, ({ ... })
bracketing, to evaluate the incoming parameter only once.  I hope that's
ok for RTEMS as well?


Corinna

ChangeLog:

	* libc/include/machine/setjmp.h (sigsetjmp): Use GCC extension to
	evaluate first parameter only once.
	(siglongjmp): Ditto.

Index: libc/include/machine/setjmp.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/machine/setjmp.h,v
retrieving revision 1.23
diff -u -p -r1.23 setjmp.h
--- libc/include/machine/setjmp.h	27 Jan 2005 23:54:42 -0000	1.23
+++ libc/include/machine/setjmp.h	9 Mar 2005 17:01:08 -0000
@@ -236,13 +236,22 @@ typedef int sigjmp_buf[_JBLEN+2];
 # define _CYGWIN_WORKING_SIGSETJMP
 #endif
 
-#define sigsetjmp(env, savemask) ((env)[_SAVEMASK] = savemask,\
-               sigprocmask (SIG_SETMASK, 0, (sigset_t *) ((env) + _SIGMASK)),\
-               setjmp (env))
+#define sigsetjmp(env, savemask) \
+            ({ \
+              sigjmp_buf *_sjbuf = &(env); \
+              ((*_sjbuf)[_SAVEMASK] = savemask,\
+              sigprocmask (SIG_SETMASK, 0, (sigset_t *)((*_sjbuf) + _SIGMASK)),\
+              setjmp (*_sjbuf)); \
+            })
 
-#define siglongjmp(env, val) ((((env)[_SAVEMASK])?\
-               sigprocmask (SIG_SETMASK, (sigset_t *) ((env) + _SIGMASK), 0):0),\
-               longjmp (env, val))
+#define siglongjmp(env, val) \
+            ({ \
+              sigjmp_buf *_sjbuf = &(env); \
+              ((((*_sjbuf)[_SAVEMASK]) ? \
+               sigprocmask (SIG_SETMASK, (sigset_t *)((*_sjbuf) + _SIGMASK), 0)\
+               : 0), \
+               longjmp (*_sjbuf, val)); \
+            })
 
 #ifdef __cplusplus
 }


-- 
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat, Inc.


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