> > 1) The strerror_r replacement, when EXTEND_STRERROR_R is defined, > > clobbers the strerror function's buffer, which it shouldn't.
Here's a followup that tries harder to clobber the strerror function's buffer. It still is not possible on Solaris <= 9 in 64-bit mode, because that libc does not export 'sys_nerr'. 2011-05-19 Bruno Haible <br...@clisp.org> strerror_r: Avoid clobbering the strerror buffer when possible. * lib/strerror.c: Define _NETBSD_SOURCE. Include <nl_types.h>. (sys_nerr, sys_errlist): New declarations. (strerror_r): Be careful not to clobber the strerror buffer on NetBSD, HP-UX, native Win32, IRIX, and 32-bit Solaris. * m4/strerror_r.m4 (gl_PREREQ_STRERROR_R): Test whether catgets exists. --- lib/strerror_r.c.orig Thu May 19 20:50:20 2011 +++ lib/strerror_r.c Thu May 19 20:49:54 2011 @@ -19,6 +19,9 @@ #include <config.h> +/* Enable declaration of sys_nerr and sys_errlist in <errno.h> on NetBSD. */ +#define _NETBSD_SOURCE 1 + /* Specification. */ #include <string.h> @@ -46,17 +49,45 @@ #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */ -# include "glthread/lock.h" - -/* Use strerror(), with locking. */ +/* Use the system's strerror(). */ # undef strerror # define USE_SYSTEM_STRERROR 1 +# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __sgi || (defined __sun && !defined _LP64) + +/* No locking needed. */ + +/* Get catgets internationalization functions. */ +# if HAVE_CATGETS +# include <nl_types.h> +# endif + +/* Get sys_nerr, sys_errlist on HP-UX (otherwise only declared in C++ mode). + Get sys_nerr, sys_errlist on IRIX (otherwise only declared with _SGIAPI). */ +# if defined __hpux || defined __sgi +extern int sys_nerr; +extern char *sys_errlist[]; +# endif + +/* Get sys_nerr on Solaris. */ +# if defined __sun && !defined _LP64 +extern int sys_nerr; +# endif + +/* Get sys_nerr, sys_errlist on native Windows. */ +# include <stdlib.h> + +# else + +# include "glthread/lock.h" + /* This lock protects the buffer returned by strerror(). We assume that no other uses of strerror() exist in the program. */ gl_lock_define_initialized(static, strerror_lock) +# endif + #endif @@ -476,6 +507,87 @@ #else /* USE_SYSTEM_STRERROR */ + /* Try to do what strerror (errnum) does, but without clobbering the + buffer used by strerror(). */ + +# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) /* NetBSD, HP-UX, native Win32 */ + + /* NetBSD: sys_nerr, sys_errlist are declared through _NETBSD_SOURCE + and <errno.h> above. + HP-UX: sys_nerr, sys_errlist are declared explicitly above. + native Win32: sys_nerr, sys_errlist are declared in <stdlib.h>. */ + if (errnum >= 0 && errnum < sys_nerr) + { +# if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) + int saved_errno = errno; +# if defined __NetBSD__ + nl_catd catd = catopen ("libc", NL_CAT_LOCALE); + const char *errmsg = + (catd != (nl_catd)-1 + ? catgets (catd, 1, errnum, sys_errlist[errnum]) + : sys_errlist[errnum]); +# endif +# if defined __hpux + nl_catd catd = catopen ("perror", NL_CAT_LOCALE); + const char *errmsg = + (catd != (nl_catd)-1 + ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum]) + : sys_errlist[errnum]); +# endif +# else + const char *errmsg = sys_errlist[errnum]; +# endif + if (errmsg == NULL || *errmsg == '\0') + ret = EINVAL; + else + { + size_t len = strlen (errmsg); + + if (len < buflen) + { + memcpy (buf, errmsg, len + 1); + ret = 0; + } + else + ret = ERANGE; + } +# if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) + if (catd != (nl_catd)-1) + catclose (catd); + errno = saved_errno; +# endif + } + else + ret = EINVAL; + +# elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */ + + /* For a valid error number, the system's strerror() function returns + a pointer to a not copied string, not to a buffer. */ + if (errnum >= 0 && errnum < sys_nerr) + { + char *errmsg = strerror (errnum); + + if (errmsg == NULL || *errmsg == '\0') + ret = EINVAL; + else + { + size_t len = strlen (errmsg); + + if (len < buflen) + { + memcpy (buf, errmsg, len + 1); + ret = 0; + } + else + ret = ERANGE; + } + } + else + ret = EINVAL; + +# else + gl_lock_lock (strerror_lock); { @@ -502,6 +614,8 @@ gl_lock_unlock (strerror_lock); +# endif + #endif return ret; --- m4/strerror_r.m4.orig Thu May 19 20:50:20 2011 +++ m4/strerror_r.m4 Thu May 19 20:48:10 2011 @@ -1,4 +1,4 @@ -# strerror_r.m4 serial 5 +# strerror_r.m4 serial 6 dnl Copyright (C) 2002, 2007-2011 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -103,5 +103,6 @@ # Prerequisites of lib/strerror_r.c. AC_DEFUN([gl_PREREQ_STRERROR_R], [ + AC_CHECK_FUNCS_ONCE([catgets]) : ]) -- In memoriam Anne Boleyn <http://en.wikipedia.org/wiki/Anne_Boleyn>