getgroups: work around FreeBSD bug
authorEric Blake <ebb9@byu.net>
Fri, 13 Nov 2009 19:53:17 +0000 (12:53 -0700)
committerIan Beckwith <ianb@erislabs.net>
Sun, 15 Nov 2009 03:17:16 +0000 (03:17 +0000)
FreeBSD 7.2 mistakenly succeeds on getgroups(-1,ptr) (POSIX
requires EINVAL failure since -1 is less than the proper result).

* lib/getgroups.c (rpl_getgroups): Work around the bug.
* m4/getgroups.m4 (gl_FUNC_GETGROUPS): Detect the bug.
* doc/posix-functions/getgroups.texi (getgroups): Document it.
* tests/test-getgroups.c (main): Fix buffer overrun.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
doc/posix-functions/getgroups.texi
lib/getgroups.c
m4/getgroups.m4
tests/test-getgroups.c

index 7d02121..a5b88a4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2009-11-13  Eric Blake  <ebb9@byu.net>
 
+       getgroups: work around FreeBSD bug
+       * lib/getgroups.c (rpl_getgroups): Work around the bug.
+       * m4/getgroups.m4 (gl_FUNC_GETGROUPS): Detect the bug.
+       * doc/posix-functions/getgroups.texi (getgroups): Document it.
+       * tests/test-getgroups.c (main): Fix buffer overrun.
+
        getgroups: avoid compilation failure
        * lib/getgroups.c (includes): Include <stdint.h> for SIZE_MAX.
        * modules/getgroups (Depends-on): Add stdint.
index 951705e..e503b22 100644 (file)
@@ -12,7 +12,11 @@ Portability problems fixed by Gnulib:
 This function is missing on some platforms:
 mingw.
 @item
-On Ultrix 4.3, @code{getgroups (0, 0)} always fails.  See macro
+On some platforms, this function fails to reject a negative count,
+even though that is less than the size that would be returned:
+FreeBSD 7.2.
+@item
+On Ultrix 4.3, @code{getgroups (0, NULL)} always fails.  See macro
 @samp{AC_FUNC_GETGROUPS}.
 @end itemize
 
index 9c0d6f7..24d7816 100644 (file)
@@ -40,6 +40,9 @@ getgroups (int n _UNUSED_PARAMETER_, GETGROUPS_T *groups _UNUSED_PARAMETER_)
 #else /* HAVE_GETGROUPS */
 
 # undef getgroups
+# ifndef GETGROUPS_ZERO_BUG
+#  define GETGROUPS_ZERO_BUG 0
+# endif
 
 /* On at least Ultrix 4.3 and NextStep 3.2, getgroups (0, NULL) always
    fails.  On other systems, it returns the number of supplemental
@@ -55,8 +58,39 @@ rpl_getgroups (int n, GETGROUPS_T *group)
   GETGROUPS_T *gbuf;
   int saved_errno;
 
-  if (n != 0)
-    return getgroups (n, group);
+  if (n < 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (n != 0 || !GETGROUPS_ZERO_BUG)
+    {
+      int result;
+      int saved_errno;
+      if (sizeof *group == sizeof *gbuf)
+        return getgroups (n, (GETGROUPS_T *) group);
+
+      if (SIZE_MAX / sizeof *gbuf <= n)
+        {
+          errno = ENOMEM;
+          return -1;
+        }
+      gbuf = malloc (n * sizeof *gbuf);
+      if (!gbuf)
+        return -1;
+      result = getgroups (n, gbuf);
+      if (0 <= result)
+        {
+          n = result;
+          while (n--)
+            group[n] = gbuf[n];
+        }
+      saved_errno = errno;
+      free (gbuf);
+      errno == saved_errno;
+      return result;
+    }
 
   n = 20;
   while (1)
index 1dd39ea..96260e3 100644 (file)
@@ -1,4 +1,4 @@
-# serial 13
+# serial 15
 
 dnl From Jim Meyering.
 dnl A wrapper around AC_FUNC_GETGROUPS.
@@ -20,6 +20,23 @@ AC_DEFUN([gl_FUNC_GETGROUPS],
   elif test "$ac_cv_func_getgroups_works" != yes; then
     AC_LIBOBJ([getgroups])
     REPLACE_GETGROUPS=1
+    AC_DEFINE([GETGROUPS_ZERO_BUG], [1], [Define this to 1 if
+      getgroups(0,NULL) does not return the number of groups.])
+  else
+    dnl Detect FreeBSD bug; POSIX requires getgroups(-1,ptr) to fail.
+    AC_CACHE_CHECK([whether getgroups handles negative values],
+      [gl_cv_func_getgroups_works],
+      [AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+        [[int size = getgroups (0, 0);
+          gid_t *list = malloc (size * sizeof *list);
+          return getgroups (-1, list) != -1;]])],
+        [gl_cv_func_getgroups_works=yes],
+        [gl_cv_func_getgroups_works=no],
+        [gl_cv_func_getgroups_works="guessing no"])])
+    if test "$gl_cv_func_getgroups_works" != yes; then
+      AC_LIBOBJ([getgroups])
+      REPLACE_GETGROUPS=1
+    fi
   fi
   test -n "$GETGROUPS_LIB" && LIBS="$GETGROUPS_LIB $LIBS"
 ])
index 8ecfb96..8d8d2ab 100644 (file)
@@ -52,7 +52,7 @@ main (int argc, char **argv _UNUSED_PARAMETER_)
     }
   ASSERT (0 <= result);
   ASSERT (result + 1 < SIZE_MAX / sizeof *groups);
-  groups = malloc (result + 1 * sizeof *groups);
+  groups = malloc ((result + 1) * sizeof *groups);
   ASSERT (groups);
   groups[result] = -1;
   /* Check for EINVAL handling.  Not all processes have supplemental