changeset 14647:4564c34c5e88

getaddrinfo: fix gai_strerror signature Several platforms declare gai_strerror to return char* rather than const char*. Worse, on mingw, if UNICODE is defined, it is defined to return WCHAR*, which means the result is in unicode but an application expecting bytes for characters will only see a one-byte answer. * m4/getaddrinfo.m4 (gl_GETADDRINFO): Detect broken signatures, and work around mingw with UNICODE defined. (gl_PREREQ_GETADDRINFO): Drop redundant decl check. * m4/netdb_h.m4 (gl_NETDB_H_DEFAULTS): Add witness. * modules/netdb (Makefile.am): Substitute it. * lib/netdb.in.h (gai_strerror): Declare replacement. * lib/gai_strerror.c (rpl_gai_strerror): Fix signature. * doc/posix-functions/gai_strerror.texi (gai_strerror): Document the fix. Signed-off-by: Eric Blake <eblake@redhat.com>
author Eric Blake <eblake@redhat.com>
date Thu, 28 Apr 2011 16:46:16 -0600
parents 2482350603ac
children 745a0964c221
files ChangeLog doc/posix-functions/gai_strerror.texi lib/gai_strerror.c lib/netdb.in.h m4/getaddrinfo.m4 m4/netdb_h.m4 modules/netdb
diffstat 7 files changed, 83 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2011-04-28  Eric Blake  <eblake@redhat.com>
 
+	getaddrinfo: fix gai_strerror signature
+	* m4/getaddrinfo.m4 (gl_GETADDRINFO): Detect broken signatures,
+	and work around mingw with UNICODE defined.
+	(gl_PREREQ_GETADDRINFO): Drop redundant decl check.
+	* m4/netdb_h.m4 (gl_NETDB_H_DEFAULTS): Add witness.
+	* modules/netdb (Makefile.am): Substitute it.
+	* lib/netdb.in.h (gai_strerror): Declare replacement.
+	* lib/gai_strerror.c (rpl_gai_strerror): Fix signature.
+	* doc/posix-functions/gai_strerror.texi (gai_strerror): Document
+	the fix.
+
 	getsockopt: avoid compiler warning
 	* lib/getsockopt.c (rpl_getsockopt): Add a cast for mingw.
 	Reported by Matthias Bolte.
--- a/doc/posix-functions/gai_strerror.texi
+++ b/doc/posix-functions/gai_strerror.texi
@@ -10,13 +10,18 @@
 @itemize
 @item
 This function is missing on some platforms:
-HP-UX 11.11, IRIX 6.5, OSF/1 4.0, Solaris 7, Cygwin 1.5.x, mingw, Interix 3.5, BeOS.
+HP-UX 11.11, IRIX 6.5, OSF/1 4.0, Solaris 7, Cygwin 1.5.x, Interix
+3.5, BeOS.
+@item
+This function is only available in @code{<ws2tcpip.h>} on some
+platforms:
+mingw.
+@item
+This function's return type is @code{char *} instead of @code{const char *}
+on some platforms:
+AIX 7.1, HP-UX 11, OSF/1 5.1, Solaris 9, mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-This function's return type is @code{char *} instead of @code{const char *}
-on some platforms:
-AIX 7.1, HP-UX 11, OSF/1 5.1, Solaris 9.
 @end itemize
--- a/lib/gai_strerror.c
+++ b/lib/gai_strerror.c
@@ -32,6 +32,22 @@
 # define N_(String) String
 #endif
 
+#if HAVE_DECL_GAI_STRERROR
+
+# include <sys/socket.h>
+# undef gai_strerror
+# if HAVE_DECL_GAI_STRERRORA
+#  define gai_strerror gai_strerrorA
+# endif
+
+const char *
+rpl_gai_strerror (int code)
+{
+  return gai_strerror (code);
+}
+
+#else /* !HAVE_DECL_GAI_STRERROR */
+
 static struct
   {
     int code;
@@ -71,6 +87,7 @@
 
   return _("Unknown error");
 }
-#ifdef _LIBC
+# ifdef _LIBC
 libc_hidden_def (gai_strerror)
-#endif
+# endif
+#endif /* !HAVE_DECL_GAI_STRERROR */
--- a/lib/netdb.in.h
+++ b/lib/netdb.in.h
@@ -167,12 +167,23 @@
 extern void freeaddrinfo (struct addrinfo *ai) _GL_ARG_NONNULL ((1));
 # endif
 
-# if !@HAVE_DECL_GAI_STRERROR@
+# if @REPLACE_GAI_STRERROR@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef gai_strerror
+#   define gai_strerror rpl_gai_strerror
+#  endif
+_GL_FUNCDECL_RPL (gai_strerror, const char *, (int ecode));
+_GL_CXXALIAS_RPL (gai_strerror, const char *, (int ecode));
+# else
+#  if !@HAVE_DECL_GAI_STRERROR@
 /* Convert error return from getaddrinfo() to a string.
    For more details, see the POSIX:2001 specification
    <http://www.opengroup.org/susv3xsh/gai_strerror.html>.  */
-extern const char *gai_strerror (int ecode);
+_GL_FUNCDECL_SYS (gai_strerror, const char *, (int ecode));
+#  endif
+_GL_CXXALIAS_SYS (gai_strerror, const char *, (int ecode));
 # endif
+_GL_CXXALIASWARN (gai_strerror);
 
 # if !@HAVE_DECL_GETNAMEINFO@
 /* Convert socket address to printable node and service names.
--- a/m4/getaddrinfo.m4
+++ b/m4/getaddrinfo.m4
@@ -1,4 +1,4 @@
-# getaddrinfo.m4 serial 24
+# getaddrinfo.m4 serial 25
 dnl Copyright (C) 2004-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,
@@ -62,9 +62,7 @@
   # We can't use AC_REPLACE_FUNCS here because gai_strerror may be an
   # inline function declared in ws2tcpip.h, so we need to get that
   # header included somehow.
-  AC_CACHE_CHECK([for gai_strerror (possibly via ws2tcpip.h)],
-    gl_cv_func_gai_strerror, [
-      AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+  AC_CHECK_DECLS([gai_strerror, gai_strerrorA], [], [break], [[
 #include <sys/types.h>
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
@@ -76,11 +74,32 @@
 #include <ws2tcpip.h>
 #endif
 #include <stddef.h>
-]], [[gai_strerror (NULL);]])],
-        [gl_cv_func_gai_strerror=yes],
-        [gl_cv_func_gai_strerror=no])])
-  if test $gl_cv_func_gai_strerror = no; then
+]])
+  if test $ac_cv_have_decl_gai_strerror = no; then
     AC_LIBOBJ([gai_strerror])
+  else
+    dnl check for correct signature
+    AC_CACHE_CHECK([for gai_strerror with POSIX signature],
+     [gl_cv_func_gai_strerror_posix_signature], [
+      AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+#include <stddef.h>
+extern const char *gai_strerror(int);]])],
+        [gl_cv_func_gai_strerror_posix_signature=yes],
+        [gl_cv_func_gai_strerror_posix_signature=no])])
+    if test $gl_cv_func_gai_strerror_posix_signature = no; then
+      REPLACE_GAI_STRERROR=1
+      AC_LIBOBJ([gai_strerror])
+    fi
   fi
 
   LIBS="$gai_saved_LIBS"
@@ -112,7 +131,7 @@
 
   AC_CHECK_HEADERS_ONCE([netinet/in.h])
 
-  AC_CHECK_DECLS([getaddrinfo, freeaddrinfo, gai_strerror, getnameinfo],,,[
+  AC_CHECK_DECLS([getaddrinfo, freeaddrinfo, getnameinfo],,,[
   /* sys/types.h is not needed according to POSIX, but the
      sys/socket.h in i386-unknown-freebsd4.10 and
      powerpc-apple-darwin5.5 required it. */
--- a/m4/netdb_h.m4
+++ b/m4/netdb_h.m4
@@ -37,4 +37,5 @@
   HAVE_DECL_GAI_STRERROR=1; AC_SUBST([HAVE_DECL_GAI_STRERROR])
   HAVE_DECL_GETADDRINFO=1;  AC_SUBST([HAVE_DECL_GETADDRINFO])
   HAVE_DECL_GETNAMEINFO=1;  AC_SUBST([HAVE_DECL_GETNAMEINFO])
+  REPLACE_GAI_STRERROR=0;   AC_SUBST([REPLACE_GAI_STRERROR])
 ])
--- a/modules/netdb
+++ b/modules/netdb
@@ -33,6 +33,7 @@
 	      -e 's|@''HAVE_DECL_GAI_STRERROR''@|$(HAVE_DECL_GAI_STRERROR)|g' \
 	      -e 's|@''HAVE_DECL_GETADDRINFO''@|$(HAVE_DECL_GETADDRINFO)|g' \
 	      -e 's|@''HAVE_DECL_GETNAMEINFO''@|$(HAVE_DECL_GETNAMEINFO)|g' \
+	      -e 's|@''REPLACE_GAI_STRERROR''@|$(REPLACE_GAI_STRERROR)|g' \
 	      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
 	      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
 	      < $(srcdir)/netdb.in.h; \