Browse Source

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 17 năm trước cách đây
mục cha
commit
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;