[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: perror bug
From: |
Bruno Haible |
Subject: |
Re: perror bug |
Date: |
Thu, 19 May 2011 20:58:35 +0200 |
User-agent: |
KMail/1.9.9 |
> > 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 <address@hidden>
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>