about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2007-12-03 22:46:10 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2007-12-03 22:46:10 +0000
commit61320c44c1c09a1e9b455771437c94174108739c (patch)
treed7cdbc3b40eec96ded0ac715ef61830c49211770
parent9794b454777867201e242c425b4fd9629c669fee (diff)
downloadzsh-61320c44c1c09a1e9b455771437c94174108739c.tar.gz
zsh-61320c44c1c09a1e9b455771437c94174108739c.tar.xz
zsh-61320c44c1c09a1e9b455771437c94174108739c.zip
24148: attempt to use strerror_r() to make errors in signal handle safer
-rw-r--r--ChangeLog5
-rw-r--r--Src/utils.c37
-rw-r--r--configure.ac2
3 files changed, 41 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 725b4be92..03a52f752 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-12-03  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 24148: configure.ac, Src/utils.c: attempt to use strerror_r()
+	to make error messages in signal handle safer.
+
 2007-12-03  Peter Stephenson  <pws@csr.com>
 
 	* 24143: Etc/zsh-development-guide, Util/.distfiles:  Remove
diff --git a/Src/utils.c b/Src/utils.c
index f9e658c0f..7c22a277f 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -255,6 +255,12 @@ zerrmsg(FILE *file, const char *fmt, va_list ap)
 {
     const char *str;
     int num;
+#ifdef HAVE_STRERROR_R
+#define ERRBUFSIZE (80)
+    int olderrno;
+    char errbuf[ERRBUFSIZE];
+#endif
+    char *errmsg;
 
     if ((unset(SHINSTDIN) || locallevel) && lineno)
 	fprintf(file, "%ld: ", (long)lineno);
@@ -304,12 +310,39 @@ zerrmsg(FILE *file, const char *fmt, va_list ap)
 		    errflag = 1;
 		    return;
 		}
+#ifdef HAVE_STRERROR_R
+		/*
+		 * There are two incompatible strerror_r()s floating round.
+		 * The GNU extension refuses to copy the message into the
+		 * buffer if it can return a constant string.  To suppress it
+		 * we need to define _XOPEN_SOURCE to 600.  I don't dare do
+		 * this because we're already depending on _GNU_SOURCE.  So
+		 * try to handle both by looking for errno being set (for the
+		 * standard version failing) or errbuf being left untouched
+		 * (for the GNU version).  One presumes that if strerror_r()
+		 * didn't copy anything to errbuf, then it's safe to
+		 * call strerror() to get the string.
+		 *
+		 * This is a mess, but it's about a decade and half
+		 * too late to shirk from messes in the source.
+		 */
+		olderrno = errno;
+		errno = 0;
+		errbuf[0] = '\0';
+		strerror_r(num, errbuf, ERRBUFSIZE);
+		if (errno || errbuf[0] == '\0')
+		    errmsg = strerror(num);
+		else
+		    errmsg = errbuf;
+		errno = olderrno;
+#else
+		errmsg = strerror(num);
+#endif
 		/* If the message is not about I/O problems, it looks better *
 		 * if we uncapitalize the first letter of the message        */
 		if (num == EIO)
-		    fputs(strerror(num), file);
+		    fputs(errmsg, file);
 		else {
-		    char *errmsg = strerror(num);
 		    fputc(tulower(errmsg[0]), file);
 		    fputs(errmsg + 1, file);
 		}
diff --git a/configure.ac b/configure.ac
index 9f5fd20bb..11a74f55a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1157,7 +1157,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
 	       getlogin getpwent getpwnam getpwuid getgrgid getgrnam \
 	       initgroups nis_list \
 	       setuid seteuid setreuid setresuid setsid \
-	       memcpy memmove strstr strerror \
+	       memcpy memmove strstr strerror strerror_r \
 	       getrlimit getrusage \
 	       setlocale \
 	       uname \