From: Bruno Haible <bruno@clisp.org>
Date: Sun, 23 Apr 2017 00:45:19 +0000 (+0200)
Subject: getlogin_r: Work around bug in Mac OS X 10.12.
X-Git-Tag: v1.0~6254
X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=63a51f5a37634098883aa83d78be90e5dffcd9ce;p=gnulib.git

getlogin_r: Work around bug in Mac OS X 10.12.

* m4/getlogin_r.m4 (gl_FUNC_GETLOGIN_R): Test also against the Mac OS X
bug.
* lib/getlogin_r.c (getlogin_r): When getlogin_r returns a string of the
given size minus 1, call getlogin_r a second time, on a larger buffer.
* modules/getlogin_r (Depends-on): Add malloca.
* doc/posix-functions/getlogin_r.texi: Mention the Mac OS X bug.
---

diff --git a/ChangeLog b/ChangeLog
index bdebb94589..25fe006255 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2017-04-22  Bruno Haible  <bruno@clisp.org>
+
+        getlogin_r: Work around bug in Mac OS X 10.12.
+        * m4/getlogin_r.m4 (gl_FUNC_GETLOGIN_R): Test also against the Mac OS X
+        bug.
+        * lib/getlogin_r.c (getlogin_r): When getlogin_r returns a string of the
+        given size minus 1, call getlogin_r a second time, on a larger buffer.
+        * modules/getlogin_r (Depends-on): Add malloca.
+        * doc/posix-functions/getlogin_r.texi: Mention the Mac OS X bug.
+
 2017-04-22  Paul Eggert  <eggert@cs.ucla.edu>
 
 	parse-datetime: fix %z and prefer signed int
diff --git a/doc/posix-functions/getlogin_r.texi b/doc/posix-functions/getlogin_r.texi
index 6efb9771ea..09aa5f1667 100644
--- a/doc/posix-functions/getlogin_r.texi
+++ b/doc/posix-functions/getlogin_r.texi
@@ -18,7 +18,7 @@ HP-UX 11.
 @item
 This function returns a truncated result, instead of failing with error code
 @code{ERANGE}, when the buffer is not large enough, on some platforms:
-OSF/1 5.1.
+Mac OS X 10.12, OSF/1 5.1.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/lib/getlogin_r.c b/lib/getlogin_r.c
index 352b0413db..230aba0ef5 100644
--- a/lib/getlogin_r.c
+++ b/lib/getlogin_r.c
@@ -25,6 +25,8 @@
 #include <errno.h>
 #include <string.h>
 
+#include "malloca.h"
+
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 # define WIN32_LEAN_AND_MEAN
 # include <windows.h>
@@ -63,9 +65,27 @@ getlogin_r (char *name, size_t size)
   /* Platform with a getlogin_r() function.  */
   int ret = getlogin_r (name, size);
 
-  if (ret == 0 && memchr (name, '\0', size) == NULL)
-    /* name contains a truncated result.  */
-    return ERANGE;
+  if (ret == 0)
+    {
+      const char *nul = memchr (name, '\0', size);
+      if (nul == NULL)
+        /* name contains a truncated result.  */
+        return ERANGE;
+      if (size > 0 && nul == name + size - 1)
+        {
+          /* strlen(name) == size-1.  Determine whether the untruncated result
+             would have had length size-1 or size.  */
+          char *room = (char *) malloca (size + 1);
+          if (room == NULL)
+            return ENOMEM;
+          ret = getlogin_r (room, size + 1);
+          /* The untruncated result should be the same as in the first call.  */
+          if (ret == 0 && memcmp (name, room, size) != 0)
+            /* The untruncated result would have been different.  */
+            ret = ERANGE;
+          freea (room);
+        }
+    }
   return ret;
 #else
   /* Platform with a getlogin() function.  */
diff --git a/m4/getlogin_r.m4 b/m4/getlogin_r.m4
index 597bcd00ba..c00a13e0f1 100644
--- a/m4/getlogin_r.m4
+++ b/m4/getlogin_r.m4
@@ -1,4 +1,4 @@
-#serial 11
+#serial 12
 
 # Copyright (C) 2005-2007, 2009-2017 Free Software Foundation, Inc.
 #
@@ -30,8 +30,8 @@ AC_DEFUN([gl_FUNC_GETLOGIN_R],
     HAVE_GETLOGIN_R=0
   else
     HAVE_GETLOGIN_R=1
-    dnl On OSF/1 5.1, getlogin_r returns a truncated result if the buffer is
-    dnl not large enough.
+    dnl On Mac OS X 10.12 and OSF/1 5.1, getlogin_r returns a truncated result
+    dnl if the buffer is not large enough.
     AC_REQUIRE([AC_CANONICAL_HOST])
     AC_CACHE_CHECK([whether getlogin_r works with small buffers],
       [gl_cv_func_getlogin_r_works],
@@ -39,15 +39,16 @@ AC_DEFUN([gl_FUNC_GETLOGIN_R],
         dnl Initial guess, used when cross-compiling.
 changequote(,)dnl
         case "$host_os" in
-                # Guess no on OSF/1.
-          osf*) gl_cv_func_getlogin_r_works="guessing no" ;;
-                # Guess yes otherwise.
-          *)    gl_cv_func_getlogin_r_works="guessing yes" ;;
+                          # Guess no on Mac OS X, OSF/1.
+          darwin* | osf*) gl_cv_func_getlogin_r_works="guessing no" ;;
+                          # Guess yes otherwise.
+          *)              gl_cv_func_getlogin_r_works="guessing yes" ;;
         esac
 changequote([,])dnl
         AC_RUN_IFELSE(
           [AC_LANG_SOURCE([[
 #include <stddef.h>
+#include <string.h>
 #include <unistd.h>
 #if !HAVE_DECL_GETLOGIN_R
 extern
@@ -63,16 +64,19 @@ main (void)
   char buf[100];
 
   if (getlogin_r (buf, 0) == 0)
-    result |= 16;
+    result |= 1;
   if (getlogin_r (buf, 1) == 0)
-    result |= 17;
+    result |= 2;
+  if (getlogin_r (buf, 100) == 0)
+    {
+      size_t n = strlen (buf);
+      if (getlogin_r (buf, n) == 0)
+        result |= 4;
+    }
   return result;
 }]])],
           [gl_cv_func_getlogin_r_works=yes],
-          [case $? in
-             16 | 17) gl_cv_func_getlogin_r_works=no ;;
-           esac
-          ],
+          [gl_cv_func_getlogin_r_works=no],
           [:])
       ])
     case "$gl_cv_func_getlogin_r_works" in
diff --git a/modules/getlogin_r b/modules/getlogin_r
index 169cb441a2..befc365544 100644
--- a/modules/getlogin_r
+++ b/modules/getlogin_r
@@ -9,6 +9,7 @@ m4/getlogin.m4
 Depends-on:
 unistd
 extensions
+malloca         [test $HAVE_GETLOGIN_R = 0 || test $REPLACE_GETLOGIN_R = 1]
 memchr          [test $HAVE_GETLOGIN_R = 0 || test $REPLACE_GETLOGIN_R = 1]
 
 configure.ac: