From 61320c44c1c09a1e9b455771437c94174108739c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 3 Dec 2007 22:46:10 +0000 Subject: [PATCH] 24148: attempt to use strerror_r() to make errors in signal handle safer --- ChangeLog | 5 +++++ Src/utils.c | 37 +++++++++++++++++++++++++++++++++++-- configure.ac | 2 +- 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 + + * 24148: configure.ac, Src/utils.c: attempt to use strerror_r() + to make error messages in signal handle safer. + 2007-12-03 Peter Stephenson * 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 \