From f99411b3b5dec88d17532160071859649fa3a26c Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Thu, 19 May 2011 20:57:21 +0200 Subject: [PATCH] strerror_r: Avoid clobbering the strerror buffer when possible. * lib/strerror.c: Define _NETBSD_SOURCE. Include . (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. --- ChangeLog | 9 +++++ lib/strerror_r.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- m4/strerror_r.m4 | 3 +- 3 files changed, 128 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 92c55b552..4e22ecba2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2011-05-19 Bruno Haible + strerror_r: Avoid clobbering the strerror buffer when possible. + * lib/strerror.c: Define _NETBSD_SOURCE. Include . + (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. + +2011-05-19 Bruno Haible + strerror_r: Fix test failure on mingw. * m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Don't define EXTEND_STRERROR_R. diff --git a/lib/strerror_r.c b/lib/strerror_r.c index aa0da372b..c4aa5d9d1 100644 --- a/lib/strerror_r.c +++ b/lib/strerror_r.c @@ -19,6 +19,9 @@ #include +/* Enable declaration of sys_nerr and sys_errlist in on NetBSD. */ +#define _NETBSD_SOURCE 1 + /* Specification. */ #include @@ -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 +# 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 + +# 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 @@ strerror_r (int errnum, char *buf, size_t buflen) #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 above. + HP-UX: sys_nerr, sys_errlist are declared explicitly above. + native Win32: sys_nerr, sys_errlist are declared in . */ + 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 @@ strerror_r (int errnum, char *buf, size_t buflen) gl_lock_unlock (strerror_lock); +# endif + #endif return ret; diff --git a/m4/strerror_r.m4 b/m4/strerror_r.m4 index 744488d84..190472c95 100644 --- a/m4/strerror_r.m4 +++ b/m4/strerror_r.m4 @@ -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 @@ changequote([,])dnl # Prerequisites of lib/strerror_r.c. AC_DEFUN([gl_PREREQ_STRERROR_R], [ + AC_CHECK_FUNCS_ONCE([catgets]) : ]) -- 2.11.0