ソースを参照

fix sigset_t size for mips (it's the only arch with 128 signals).
fix _NSIG for it.
better document what's going on in sigaction().
seems to not induce any actual code changes (sans mips).

Denis Vlasenko 15 年 前
コミット
83eb4d5219

+ 13 - 6
libc/signal/sigaction.c

@@ -43,25 +43,32 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
 {
 	int result;
 	struct kernel_sigaction kact, koact;
+	enum {
+		/* We try hard to actually have them equal,
+		 * but just for paranoid reasons, be safe */
+		SIGSET_MIN_SIZE = sizeof(kact.sa_mask) < sizeof(act->sa_mask)
+				? sizeof(kact.sa_mask) : sizeof(act->sa_mask)
+	};
 
 	if (act) {
 		kact.k_sa_handler = act->sa_handler;
-		memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
+		memcpy (&kact.sa_mask, &act->sa_mask, SIGSET_MIN_SIZE);
 		kact.sa_flags = act->sa_flags;
 # ifdef HAVE_SA_RESTORER
 		kact.sa_restorer = act->sa_restorer;
 # endif
 	}
 
-	/* XXX The size argument hopefully will have to be changed to the
-	   real size of the user-level sigset_t.  */
+	/* NB: kernel (as of 2.6.25) will return EINVAL
+	 * if sizeof(kact.sa_mask) does not match kernel's sizeof(sigset_t) */
 	result = __syscall_rt_sigaction(sig,
-			       act ? __ptrvalue (&kact) : NULL,
-			       oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);
+			act ? __ptrvalue (&kact) : NULL,
+			oact ? __ptrvalue (&koact) : NULL,
+			sizeof(kact.sa_mask));
 
 	if (oact && result >= 0) {
 		oact->sa_handler = koact.k_sa_handler;
-		memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
+		memcpy (&oact->sa_mask, &koact.sa_mask, SIGSET_MIN_SIZE);
 		oact->sa_flags = koact.sa_flags;
 # ifdef HAVE_SA_RESTORER
 		oact->sa_restorer = koact.sa_restorer;

+ 30 - 23
libc/sysdeps/linux/arm/sigaction.c

@@ -51,34 +51,41 @@ int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oa
 {
     int result;
     struct kernel_sigaction kact, koact;
-
-    if (act) {
-	kact.k_sa_handler = act->sa_handler;
-	memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
-	kact.sa_flags = act->sa_flags;
+	enum {
+		SIGSET_MIN_SIZE = sizeof(kact.sa_mask) < sizeof(act->sa_mask)
+				? sizeof(kact.sa_mask) : sizeof(act->sa_mask)
+	};
+
+	if (act) {
+		kact.k_sa_handler = act->sa_handler;
+		memcpy (&kact.sa_mask, &act->sa_mask, SIGSET_MIN_SIZE);
+		kact.sa_flags = act->sa_flags;
 # ifdef HAVE_SA_RESTORER
-	if (kact.sa_flags & SA_RESTORER) {
-	    kact.sa_restorer = act->sa_restorer;
-	} else {
-	    kact.sa_restorer = choose_restorer (kact.sa_flags);
-	    kact.sa_flags |= SA_RESTORER;
-	}
+		if (kact.sa_flags & SA_RESTORER) {
+			kact.sa_restorer = act->sa_restorer;
+		} else {
+			kact.sa_restorer = choose_restorer (kact.sa_flags);
+			kact.sa_flags |= SA_RESTORER;
+		}
 # endif
-    }
+	}
 
-    /* XXX The size argument hopefully will have to be changed to the
-       real size of the user-level sigset_t.  */
-    result = __syscall_rt_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
-	    oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);
-    if (oact && result >= 0) {
-	oact->sa_handler = koact.k_sa_handler;
-	memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
-	oact->sa_flags = koact.sa_flags;
+	/* NB: kernel (as of 2.6.25) will return EINVAL
+	 * if sizeof(kact.sa_mask) does not match kernel's sizeof(sigset_t) */
+	result = __syscall_rt_sigaction(sig,
+			act ? __ptrvalue (&kact) : NULL,
+			oact ? __ptrvalue (&koact) : NULL,
+			sizeof(kact.sa_mask));
+
+	if (oact && result >= 0) {
+		oact->sa_handler = koact.k_sa_handler;
+		memcpy (&oact->sa_mask, &koact.sa_mask, SIGSET_MIN_SIZE);
+		oact->sa_flags = koact.sa_flags;
 # ifdef HAVE_SA_RESTORER
-	oact->sa_restorer = koact.sa_restorer;
+		oact->sa_restorer = koact.sa_restorer;
 # endif
-    }
-    return result;
+	}
+	return result;
 }
 
 

+ 12 - 6
libc/sysdeps/linux/avr32/sigaction.c

@@ -27,10 +27,14 @@ int __libc_sigaction(int signum, const struct sigaction *act,
 {
 	struct kernel_sigaction kact, koact;
 	int result;
+	enum {
+		SIGSET_MIN_SIZE = sizeof(kact.sa_mask) < sizeof(act->sa_mask)
+				? sizeof(kact.sa_mask) : sizeof(act->sa_mask)
+	};
 
 	if (act) {
 		kact.k_sa_handler = act->sa_handler;
-		memcpy(&kact.sa_mask, &act->sa_mask, sizeof (kact.sa_mask));
+		memcpy(&kact.sa_mask, &act->sa_mask, SIGSET_MIN_SIZE);
 		kact.sa_flags = act->sa_flags;
 		if (kact.sa_flags & SA_RESTORER)
 			kact.sa_restorer = act->sa_restorer;
@@ -39,14 +43,16 @@ int __libc_sigaction(int signum, const struct sigaction *act,
 		kact.sa_flags |= SA_RESTORER;
 	}
 
-	result = __syscall_rt_sigaction(signum, act ? __ptrvalue(&kact) : NULL,
-					oldact ? __ptrvalue(&koact) : NULL,
-					_NSIG / 8);
+	/* NB: kernel (as of 2.6.25) will return EINVAL
+	 * if sizeof(kact.sa_mask) does not match kernel's sizeof(sigset_t) */
+	result = __syscall_rt_sigaction(signum,
+			act ? __ptrvalue(&kact) : NULL,
+			oldact ? __ptrvalue(&koact) : NULL,
+			sizeof(kact.sa_mask));
 
 	if (oldact && result >= 0) {
 		oldact->sa_handler = koact.k_sa_handler;
-		memcpy(&oldact->sa_mask, &koact.sa_mask,
-		       sizeof(oldact->sa_mask));
+		memcpy(&oldact->sa_mask, &koact.sa_mask, SIGSET_MIN_SIZE);
 		oldact->sa_flags = koact.sa_flags;
 		oldact->sa_restorer = koact.sa_restorer;
 	}

+ 9 - 2
libc/sysdeps/linux/common/bits/kernel_sigaction.h

@@ -7,6 +7,10 @@
 #undef NO_OLD_SIGACTION
 
 #if defined(__mips__)
+/* We have libc/sysdeps/linux/mips/bits/kernel_sigaction.h,
+ * so this should never be used. Lets see whether it is true. */
+struct BUG_is_here { char BUG_is_here[-1]; };
+
 #undef HAVE_SA_RESTORER
 /* This is the sigaction structure from the Linux 2.1.24 kernel.  */
 #include <sgidefs.h>
@@ -18,11 +22,9 @@ struct old_kernel_sigaction {
 #define _KERNEL_NSIG           128
 #define _KERNEL_NSIG_BPW       32
 #define _KERNEL_NSIG_WORDS     (_KERNEL_NSIG / _KERNEL_NSIG_BPW)
-
 typedef struct {
     unsigned long sig[_KERNEL_NSIG_WORDS];
 } kernel_sigset_t;
-
 /* This is the sigaction structure from the Linux 2.1.68 kernel.  */
 struct kernel_sigaction {
     unsigned int    sa_flags;
@@ -31,7 +33,9 @@ struct kernel_sigaction {
     void            (*sa_restorer)(void);
     int             s_resv[1]; /* reserved */
 };
+
 #elif defined(__ia64__)
+
 #define NO_OLD_SIGACTION
 #undef HAVE_SA_RESTORER
 struct kernel_sigaction {
@@ -39,7 +43,9 @@ struct kernel_sigaction {
 	unsigned long sa_flags;
 	sigset_t sa_mask;
 };
+
 #else
+
 #define HAVE_SA_RESTORER
 /* This is the sigaction structure from the Linux 2.1.20 kernel.  */
 struct old_kernel_sigaction {
@@ -55,6 +61,7 @@ struct kernel_sigaction {
     void (*sa_restorer) (void);
     sigset_t sa_mask;
 };
+
 #endif
 
 #ifndef NO_OLD_SIGACTION

+ 20 - 11
libc/sysdeps/linux/common/bits/sigset.h

@@ -23,15 +23,24 @@
 typedef int __sig_atomic_t;
 
 /* A 'sigset_t' has a bit for each signal.
- * Signal 0 does not exist, so we have signals 1..64.
- * glibc has space for 1024 signals (!), but all arches supported
- * by Linux have 64 signals only.
- * See, for example, _NSIG (defined to 65) in signum.h
+ * glibc has space for 1024 signals (!), but most arches supported
+ * by Linux have 64 signals, and only MIPS has 128.
+ * There seems to be some historical baggage in sparc[64]
+ * where they might have (or had in the past) 32 signals only,
+ * I hope it's irrelevant now.
+ * Signal 0 does not exist, so we have signals 1..64, not 0..63.
+ * Note that struct sigaction has embedded sigset_t,
+ * and this necessitates translation in sigaction()
+ * to convert it to struct kernel_sigaction.
+ * See libc/.../sigaction.c, libc/.../kernel_sigaction.h
  */
-
-# define _SIGSET_NWORDS	(64 / (8 * sizeof (unsigned long int)))
+#if defined(__mips__)
+# define _SIGSET_NWORDS	(128 / (8 * sizeof (unsigned long)))
+#else
+# define _SIGSET_NWORDS	(64 / (8 * sizeof (unsigned long)))
+#endif
 typedef struct {
-	unsigned long int __val[_SIGSET_NWORDS];
+	unsigned long __val[_SIGSET_NWORDS];
 } __sigset_t;
 
 #endif
@@ -53,10 +62,10 @@ typedef struct {
 /* Return a mask that includes the bit for SIG only.  */
 /* Unsigned cast ensures shift/mask insns are used.  */
 # define __sigmask(sig) \
-  (((unsigned long int) 1) << ((unsigned)((sig) - 1) % (8 * sizeof (unsigned long int))))
+  (((unsigned long) 1) << ((unsigned)((sig) - 1) % (8 * sizeof (unsigned long))))
 
 /* Return the word index for SIG.  */
-# define __sigword(sig)	((unsigned)((sig) - 1) / (8 * sizeof (unsigned long int)))
+# define __sigword(sig)	((unsigned)((sig) - 1) / (8 * sizeof (unsigned long)))
 
 /* gcc 4.3.1 is not clever enough to optimize for _SIGSET_NWORDS == 1 and 2,
  * which are about the only values which can be there */
@@ -161,8 +170,8 @@ libc_hidden_proto(__sigdelset)
 _EXTERN_INLINE int							\
 NAME (CONST __sigset_t *__set, int __sig)				\
 {									\
-	unsigned long int __mask = __sigmask (__sig);			\
-	unsigned long int __word = __sigword (__sig);			\
+	unsigned long __mask = __sigmask (__sig);			\
+	unsigned long __word = __sigword (__sig);			\
 	return BODY;							\
 }
 

+ 34 - 28
libc/sysdeps/linux/i386/sigaction.c

@@ -39,38 +39,44 @@ extern void restore (void) __asm__ ("__restore") attribute_hidden;
    If OACT is not NULL, put the old action for SIG in *OACT.  */
 int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
 {
-    int result;
-    struct kernel_sigaction kact, koact;
+	int result;
+	struct kernel_sigaction kact, koact;
+	enum {
+		SIGSET_MIN_SIZE = sizeof(kact.sa_mask) < sizeof(act->sa_mask)
+				? sizeof(kact.sa_mask) : sizeof(act->sa_mask)
+	};
 
 #ifdef SIGCANCEL
-    if (sig == SIGCANCEL) {
-	__set_errno (EINVAL);
-	return -1;
-    }
+	if (sig == SIGCANCEL) {
+		__set_errno (EINVAL);
+		return -1;
+	}
 #endif
 
-    if (act) {
-	kact.k_sa_handler = act->sa_handler;
-	memcpy (&kact.sa_mask, &act->sa_mask, sizeof (kact.sa_mask));
-	kact.sa_flags = act->sa_flags;
-
-	kact.sa_flags = act->sa_flags | SA_RESTORER;
-	kact.sa_restorer = ((act->sa_flags & SA_SIGINFO)
-		? &restore_rt : &restore);
-    }
-
-    /* XXX The size argument hopefully will have to be changed to the
-       real size of the user-level sigset_t.  */
-    result = __syscall_rt_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
-	    oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);
-
-    if (oact && result >= 0) {
-	oact->sa_handler = koact.k_sa_handler;
-	memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (oact->sa_mask));
-	oact->sa_flags = koact.sa_flags;
-	oact->sa_restorer = koact.sa_restorer;
-    }
-    return result;
+	if (act) {
+		kact.k_sa_handler = act->sa_handler;
+		memcpy (&kact.sa_mask, &act->sa_mask, SIGSET_MIN_SIZE);
+		kact.sa_flags = act->sa_flags;
+
+		kact.sa_flags = act->sa_flags | SA_RESTORER;
+		kact.sa_restorer = ((act->sa_flags & SA_SIGINFO)
+			? &restore_rt : &restore);
+	}
+
+	/* NB: kernel (as of 2.6.25) will return EINVAL
+	 * if sizeof(kact.sa_mask) does not match kernel's sizeof(sigset_t) */
+	result = __syscall_rt_sigaction(sig,
+			act ? __ptrvalue (&kact) : NULL,
+			oact ? __ptrvalue (&koact) : NULL,
+			sizeof(kact.sa_mask));
+
+	if (oact && result >= 0) {
+		oact->sa_handler = koact.k_sa_handler;
+		memcpy (&oact->sa_mask, &koact.sa_mask, SIGSET_MIN_SIZE);
+		oact->sa_flags = koact.sa_flags;
+		oact->sa_restorer = koact.sa_restorer;
+	}
+	return result;
 }
 
 

+ 1 - 1
libc/sysdeps/linux/mips/bits/signum.h

@@ -65,7 +65,7 @@
 #define SIGXFSZ		31	/* File size limit exceeded (4.2 BSD).  */
 
 
-#define _NSIG		128	/* Biggest signal number + 1
+#define _NSIG		129	/* Biggest signal number + 1
 				   (including real-time signals).  */
 
 #define SIGRTMIN	(__libc_current_sigrtmin ())

+ 29 - 23
libc/sysdeps/linux/mips/sigaction.c

@@ -47,36 +47,42 @@ static void restore (void) __asm__ ("__restore");
    If OACT is not NULL, put the old action for SIG in *OACT.  */
 int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
 {
-    int result;
-    struct kernel_sigaction kact, koact;
-
-    if (act) {
-	kact.k_sa_handler = act->sa_handler;
-	memcpy (&kact.sa_mask, &act->sa_mask, sizeof (kact.sa_mask));
-	kact.sa_flags = act->sa_flags;
+	int result;
+	struct kernel_sigaction kact, koact;
+	enum {
+		SIGSET_MIN_SIZE = sizeof(kact.sa_mask) < sizeof(act->sa_mask)
+				? sizeof(kact.sa_mask) : sizeof(act->sa_mask)
+	};
+
+	if (act) {
+		kact.k_sa_handler = act->sa_handler;
+		memcpy (&kact.sa_mask, &act->sa_mask, SIGSET_MIN_SIZE);
+		kact.sa_flags = act->sa_flags;
 # ifdef HAVE_SA_RESTORER
 #  if _MIPS_SIM == _ABIO32
-	kact.sa_restorer = act->sa_restorer;
+		kact.sa_restorer = act->sa_restorer;
 #  else
-	kact.sa_restorer = &restore_rt;
+		kact.sa_restorer = &restore_rt;
 #  endif
 # endif
-    }
-
-    /* XXX The size argument hopefully will have to be changed to the
-       real size of the user-level sigset_t.  */
-    result = __syscall_rt_sigaction(sig, act ? __ptrvalue (&kact) : NULL,
-	    oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);
-
-    if (oact && result >= 0) {
-	oact->sa_handler = koact.k_sa_handler;
-	memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (oact->sa_mask));
-	oact->sa_flags = koact.sa_flags;
+	}
+
+	/* NB: kernel (as of 2.6.25) will return EINVAL
+	 * if sizeof(kact.sa_mask) does not match kernel's sizeof(sigset_t) */
+	result = __syscall_rt_sigaction(sig,
+			act ? __ptrvalue (&kact) : NULL,
+			oact ? __ptrvalue (&koact) : NULL,
+			sizeof(kact.sa_mask));
+
+	if (oact && result >= 0) {
+		oact->sa_handler = koact.k_sa_handler;
+		memcpy (&oact->sa_mask, &koact.sa_mask, SIGSET_MIN_SIZE);
+		oact->sa_flags = koact.sa_flags;
 # ifdef HAVE_SA_RESTORER
-	oact->sa_restorer = koact.sa_restorer;
+		oact->sa_restorer = koact.sa_restorer;
 # endif
-    }
-    return result;
+	}
+	return result;
 }
 
 

+ 13 - 7
libc/sysdeps/linux/x86_64/sigaction.c

@@ -50,23 +50,29 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
 {
 	int result;
 	struct kernel_sigaction kact, koact;
+	enum {
+		SIGSET_MIN_SIZE = sizeof(kact.sa_mask) < sizeof(act->sa_mask)
+				? sizeof(kact.sa_mask) : sizeof(act->sa_mask)
+	};
 
 	if (act) {
 		kact.k_sa_handler = act->sa_handler;
-		memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
+		memcpy (&kact.sa_mask, &act->sa_mask, SIGSET_MIN_SIZE);
 		kact.sa_flags = act->sa_flags | SA_RESTORER;
 
 		kact.sa_restorer = &restore_rt;
 	}
 
-	/* XXX The size argument hopefully will have to be changed to the
-	   real size of the user-level sigset_t.  */
-	result = INLINE_SYSCALL (rt_sigaction, 4,
-	                         sig, act ? __ptrvalue (&kact) : NULL,
-	                         oact ? __ptrvalue (&koact) : NULL, _NSIG / 8);
+	/* NB: kernel (as of 2.6.25) will return EINVAL
+	 * if sizeof(kact.sa_mask) does not match kernel's sizeof(sigset_t) */
+	result = INLINE_SYSCALL (rt_sigaction, 4, sig,
+	                act ? __ptrvalue (&kact) : NULL,
+	                oact ? __ptrvalue (&koact) : NULL,
+			sizeof(kact.sa_mask));
+
 	if (oact && result >= 0) {
 		oact->sa_handler = koact.k_sa_handler;
-		memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
+		memcpy (&oact->sa_mask, &koact.sa_mask, SIGSET_MIN_SIZE);
 		oact->sa_flags = koact.sa_flags;
 		oact->sa_restorer = koact.sa_restorer;
 	}

+ 18 - 11
libc/sysdeps/linux/xtensa/sigaction.c

@@ -20,14 +20,18 @@ extern void __default_sa_restorer (void);
 /* Experimentally off - libc_hidden_proto(memcpy) */
 
 int __libc_sigaction (int signum, const struct sigaction *act,
-					  struct sigaction *oldact)
+					  struct sigaction *oact)
 {
-	struct kernel_sigaction kact, koldact;
+	struct kernel_sigaction kact, koact;
 	int result;
+	enum {
+		SIGSET_MIN_SIZE = sizeof(kact.sa_mask) < sizeof(act->sa_mask)
+				? sizeof(kact.sa_mask) : sizeof(act->sa_mask)
+	};
 
 	if (act) {
 		kact.k_sa_handler = act->sa_handler;
-		memcpy(&kact.sa_mask, &act->sa_mask, sizeof (kact.sa_mask));
+		memcpy(&kact.sa_mask, &act->sa_mask, SIGSET_MIN_SIZE);
 		kact.sa_flags = act->sa_flags;
 
 		if (kact.sa_flags & SA_RESTORER) {
@@ -38,15 +42,18 @@ int __libc_sigaction (int signum, const struct sigaction *act,
 		}
 	}
 
-	result = __syscall_rt_sigaction(signum, act ? __ptrvalue (&kact) : NULL,
-									oldact ? __ptrvalue (&koldact) : NULL,
-									_NSIG / 8);
+	/* NB: kernel (as of 2.6.25) will return EINVAL
+	 * if sizeof(kact.sa_mask) does not match kernel's sizeof(sigset_t) */
+	result = __syscall_rt_sigaction(signum,
+			act ? __ptrvalue (&kact) : NULL,
+			oact ? __ptrvalue (&koact) : NULL,
+			sizeof(kact.sa_mask));
 
-	if (oldact && result >= 0) {
-		oldact->sa_handler = koldact.k_sa_handler;
-		memcpy(&oldact->sa_mask, &koldact.sa_mask, sizeof(oldact->sa_mask));
-		oldact->sa_flags = koldact.sa_flags;
-		oldact->sa_restorer = koldact.sa_restorer;
+	if (oact && result >= 0) {
+		oact->sa_handler = koact.k_sa_handler;
+		memcpy(&oact->sa_mask, &koact.sa_mask, SIGSET_MIN_SIZE);
+		oact->sa_flags = koact.sa_flags;
+		oact->sa_restorer = koact.sa_restorer;
 	}
 
 	return result;