blob: 4d28101b46f61f39122fb364e7b83511ef09a1fe [file] [log] [blame]
From b5891a57b586ef6ff78bb752d62915b78cd58d7e Mon Sep 17 00:00:00 2001
From: Zack Weinberg <zackw@panix.com>
Date: Sun, 2 Apr 2023 15:07:58 -0400
Subject: [PATCH 12/29] Overhaul AC_TYPE_GETGROUPS and AC_FUNC_GETGROUPS.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
AC_TYPE_GETGROUPS is the last remaining use of AC_EGREP_HEADER in
stock Autoconf macros. It uses it only when cross compiling, as a
fallback from an AC_RUN_IFELSE check, testing for a bug in system
headers from the late 1980s or early 1990s, where gid_t *existed*
but the second argument to getgroups needed to be an array of int,
and this didnt cause a compile error (i.e. the system headers
declare getgroups with no prototype or an incorrect prototype).
AC_FUNC_GETGROUPS also uses AC_RUN_IFELSE to test for obscure
problems specific to long-obsolete Unixes.
The downsides of AC_RUN_IFELSE and AC_EGREP_HEADER seem more severe
than the chances of someone compiling a current-generation program,
that uses getgroups, on an OS old enough to have one of the really
nasty bugs. Accordingly, this patch changes AC_FUNC_GETGROUPS to use
a host_os-based *blacklist* both in native and cross compilation.
This is limited to the two host_os values for which either our old
code, or Gnulib, documented a serious bug: ultrix* and nextstep*.
Currently it does not try to pin down the exact version ranges subject
to the bugs that would require research by someone with access to
the full history of these OSes.
An incorrect guess by this blacklist can be overridden by setting
ac_cv_func_getgroups_works in config.site. AC_TYPE_GETGROUPS, for its
part, now does a series of regular old AC_COMPILE_IFELSE checks to
probe the prototype of getgroups, and considers that good enough.
While I was in there I noticed that AC_FUNC_GETGROUPS does not
AC_SUBST a documented output variable, and that the name of this
variable is misspelled in the manual.
* lib/autoconf/functions.m4 (AC_FUNC_GETGROUPS): Use AC_SEARCH_LIBS
to probe for getgroups. Use an AC_CANONICAL_HOST-based blacklist
for bug detection, not AC_RUN_IFELSE. AC_SUBST the GETGROUPS_LIB
output variable.
* lib/autoconf/types.m4 (AC_TYPE_GETGROUPS): Check only the prototype
of getgroups, using AC_COMPILE_IFELSE; do not use either AC_RUN_IFELSE
or AC_EGREP_HEADER.
* doc/autoconf.texi: Update to match. Correct misspelling of
GETGROUPS_LIB.
* tests.local.at (_AT_CHECK_ENV): Allow GETGROUPS_LIB output variable.
Upstream-Status: Backport
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
NEWS | 11 +++++
doc/autoconf.texi | 25 ++++++----
lib/autoconf/functions.m4 | 61 ++++++++++++------------
lib/autoconf/types.m4 | 97 ++++++++++++++++++++++++---------------
tests/local.at | 2 +-
5 files changed, 120 insertions(+), 76 deletions(-)
diff --git a/NEWS b/NEWS
index 53c57ff59..8e4ecc1bf 100644
--- a/NEWS
+++ b/NEWS
@@ -38,6 +38,17 @@ GNU Autoconf NEWS - User visible changes.
This matters only for uses that, contrary to the documentation
and despite warnings, use m4_divert with numbered diversions.
+*** AC_FUNC_GETGROUPS and AC_TYPE_GETGROUPS no longer run test programs.
+ These macros were testing for OS bugs that we believe are at least
+ twenty years in the past. Most operating systems are now trusted to
+ provide an accurate prototype for getgroups in unistd.h, and to
+ implement it as specified in POSIX.
+
+ AC_FUNC_GETGROUPS still includes a short blacklist of OSes with
+ known, severe bugs in getgroups. It can be overridden using
+ config.site. If you encounter a mistake in this blacklist
+ please report it to bug-autoconf.
+
** New features
*** New macro AC_SYS_YEAR2038.
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 037c8055f..5d5f613e6 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -5257,17 +5257,26 @@ and also contains workarounds for other portability problems of
@defmac AC_FUNC_GETGROUPS
@acindex{FUNC_GETGROUPS}
@cvindex HAVE_GETGROUPS
-@ovindex GETGROUPS_LIBS
+@ovindex GETGROUPS_LIB
@c @fuindex getgroups
@prindex @code{getgroups}
@caindex func_getgroups_works
-If the @code{getgroups} function is available and works,
-define @code{HAVE_GETGROUPS}. Set @code{GETGROUPS_LIBS} to any libraries
-needed to get that function. This macro runs @code{AC_TYPE_GETGROUPS}.
-
-This macro is obsolescent. New programs need not use this macro. But
-they may want to use the Gnulib module @code{getgroups}, which provides
-workarounds to other portability problems of this function.
+Perform all the checks performed by @code{AC_TYPE_GETGROUPS}
+(@pxref{AC_TYPE_GETGROUPS}).
+Then, if the @code{getgroups} function is available
+and known to work correctly, define @code{HAVE_GETGROUPS}.
+Set the output variable @code{GETGROUPS_LIB} to any libraries
+needed to get that function.
+
+This macro relies on a list of systems with known, serious bugs in
+@code{getgroups}. If this list mis-identifies your system's
+@code{getgroups} as buggy, or as not buggy, you can override it by
+setting the cache variable @code{ac_cv_func_getgroups_works} in a
+@file{config.site} file (@pxref{Site Defaults}). Please also report the
+error to @email{bug-autoconf@@gnu.org, the Autoconf Bugs mailing list}.
+
+The Gnulib module @code{getgroups} provides workarounds for additional,
+less severe portability problems with this function.
@end defmac
@anchor{AC_FUNC_GETLOADAVG}
diff --git a/lib/autoconf/functions.m4 b/lib/autoconf/functions.m4
index 655d6ba8f..74512e97d 100644
--- a/lib/autoconf/functions.m4
+++ b/lib/autoconf/functions.m4
@@ -698,47 +698,46 @@ AS_IF([test "$ac_cv_func_fseeko_ftello" = "need _LARGEFILE_SOURCE"],
# When cross-compiling, assume getgroups is broken.
AN_FUNCTION([getgroups], [AC_FUNC_GETGROUPS])
AC_DEFUN([AC_FUNC_GETGROUPS],
-[AC_REQUIRE([AC_TYPE_GETGROUPS])dnl
-AC_REQUIRE([AC_TYPE_SIZE_T])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
-AC_CHECK_FUNC(getgroups)
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_TYPE_GETGROUPS])dnl
-# If we don't yet have getgroups, see if it's in -lbsd.
+# On older systems getgroups might be in -lbsd.
# This is reported to be necessary on an ITOS 3000WS running SEIUX 3.1.
ac_save_LIBS=$LIBS
-if test $ac_cv_func_getgroups = no; then
- AC_CHECK_LIB(bsd, getgroups, [GETGROUPS_LIB=-lbsd])
-fi
-
-# Run the program to test the functionality of the system-supplied
-# getgroups function only if there is such a function.
+LIBS=
+GETGROUPS_LIB=
+AC_SEARCH_LIBS([getgroups], [bsd],
+ [test "$ac_res" = "none required" || GETGROUPS_LIB="$ac_res"
+ ac_cv_func_getgroups=yes],
+ [ac_cv_func_getgroups=no])
+LIBS=$ac_save_LIBS
+AC_SUBST([GETGROUPS_LIB])
+
+# Known severe bugs in getgroups on particular systems.
+# - On Ultrix 4.3 and NextSTEP 3.2, getgroups (0, 0) is reported to
+# fail, rather than returning the number of supplementary groups as
+# it ought to. We do not know the exact range of releases affected
+# in either case.
+# We currently reject all versions of the systems with known bugs, and
+# no other systems. Please send corrections to bug-autoconf@gnu.org.
if test $ac_cv_func_getgroups = yes; then
+ # This AC_CACHE_CHECK exists so that one may override an incorrect
+ # guess by setting ac_cv_func_getgroups_works in a config.site file.
AC_CACHE_CHECK([for working getgroups], ac_cv_func_getgroups_works,
- [AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
- [[/* On Ultrix 4.3, getgroups (0, 0) always fails. */
- return getgroups (0, 0) == -1;]])],
- [ac_cv_func_getgroups_works=yes],
- [ac_cv_func_getgroups_works=no],
- [case "$host_os" in # ((
- # Guess yes on glibc systems.
- *-gnu*) ac_cv_func_getgroups_works="guessing yes" ;;
- # If we don't know, assume the worst.
- *) ac_cv_func_getgroups_works="guessing no" ;;
- esac])
- ])
+ [AS_CASE([$host_os],
+ [ultrix* | nextstep*],
+ [ac_cv_func_getgroups_works=no # getgroups(0,0) fails
+],
+ [ac_cv_func_getgroups_works=yes])])
else
ac_cv_func_getgroups_works=no
fi
-case "$ac_cv_func_getgroups_works" in
- *yes)
- AC_DEFINE(HAVE_GETGROUPS, 1,
- [Define to 1 if your system has a working 'getgroups' function.])
- ;;
-esac
-LIBS=$ac_save_LIBS
+if test $ac_cv_func_getgroups_works = yes; then
+ AC_DEFINE(HAVE_GETGROUPS, 1,
+ [Define to 1 if your system has a working 'getgroups' function.])
+fi
])# AC_FUNC_GETGROUPS
-
# _AC_LIBOBJ_GETLOADAVG
# ---------------------
# Set up the AC_LIBOBJ replacement of 'getloadavg'.
diff --git a/lib/autoconf/types.m4 b/lib/autoconf/types.m4
index ef2456135..af3872b2f 100644
--- a/lib/autoconf/types.m4
+++ b/lib/autoconf/types.m4
@@ -258,44 +258,69 @@ AN_IDENTIFIER([ptrdiff_t], [AC_CHECK_TYPES])
# AC_TYPE_GETGROUPS
# -----------------
AC_DEFUN([AC_TYPE_GETGROUPS],
+dnl We now unconditionally assume that if <unistd.h> has a prototype for
+dnl getgroups, it is accurate; and that if <unistd.h> does _not_ declare
+dnl getgroups with a prototype, the second argument is an array of int.
+dnl (Older versions of Autoconf made these assumptions only when cross
+dnl compiling.) See AC_FUNC_GETGROUPS, over in functions.m4, for why
+dnl this uses AC_COMPILE_IFELSE rather than AC_LINK_IFELSE.
[AC_REQUIRE([AC_TYPE_UID_T])dnl
-AC_CACHE_CHECK(type of array argument to getgroups, ac_cv_type_getgroups,
-[AC_RUN_IFELSE([AC_LANG_SOURCE(
-[[/* Thanks to Mike Rendell for this test. */
-]AC_INCLUDES_DEFAULT[
-#define NGID 256
-#undef MAX
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-
-int
-main (void)
-{
- gid_t gidset[NGID];
- int i, n;
- union { gid_t gval; long int lval; } val;
-
- val.lval = -1;
- for (i = 0; i < NGID; i++)
- gidset[i] = val.gval;
- n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1,
- gidset);
- /* Exit non-zero if getgroups seems to require an array of ints. This
- happens when gid_t is short int but getgroups modifies an array
- of ints. */
- return n > 0 && gidset[n] != val.gval;
-}]])],
- [ac_cv_type_getgroups=gid_t],
- [ac_cv_type_getgroups=int],
- [ac_cv_type_getgroups=cross])
-if test $ac_cv_type_getgroups = cross; then
- dnl When we can't run the test program (we are cross compiling), presume
- dnl that <unistd.h> has either an accurate prototype for getgroups or none.
- dnl Old systems without prototypes probably use int.
- AC_EGREP_HEADER([getgroups.*int.*gid_t], unistd.h,
- ac_cv_type_getgroups=gid_t, ac_cv_type_getgroups=int)
-fi])
+AC_CACHE_CHECK([type of array argument to getgroups], ac_cv_type_getgroups,
+[# If AC_TYPE_UID_T says there isn't any gid_t typedef, then we can skip
+# everything below.
+AS_IF([test $ac_cv_type_gid_t = no],
+ [ac_cv_type_getgroups=int],
+ [# Test programs below rely on strict type checking of extern declarations:
+ # 'extern int getgroups(int, int *); extern int getgroups(int, pid_t *);'
+ # is valid in C89 if and only if pid_t is a typedef for int. Unlike
+ # anything involving either an assignment or a function call, compilers
+ # tend to make this kind of type mismatch a hard error, not just an
+ # "incompatible pointer types" warning.
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[AC_INCLUDES_DEFAULT
+[extern int getgroups(int, gid_t *);]],
+[[return !(getgroups(0, 0) >= 0);]])],
+ [ac_getgroups_gidarray=yes],
+ [ac_getgroups_gidarray=no])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[AC_INCLUDES_DEFAULT
+[extern int getgroups(int, int *);]],
+[[return !(getgroups(0, 0) >= 0);]])],
+ [ac_getgroups_intarray=yes],
+ [ac_getgroups_intarray=no])
+
+ AS_CASE([int:$ac_getgroups_intarray,gid:$ac_getgroups_gidarray],
+ [int:yes,gid:no], [ac_cv_type_getgroups=int],
+ [int:no,gid:yes], [ac_cv_type_getgroups=gid_t],
+ [int:yes,gid:yes], [
+ # Both programs compiled - this means *either* that getgroups
+ # was declared with no prototype, in which case we should use int,
+ # or that it was declared prototyped but gid_t is a typedef for int,
+ # in which case we should use gid_t. Distinguish the two cases
+ # by testing if the compiler catches a blatantly incorrect function
+ # signature for getgroups.
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[AC_INCLUDES_DEFAULT
+[extern int getgroups(int, float);]],
+[[return !(getgroups(0, 0) >= 0);]])], [
+ # Compiler did not catch incorrect argument list;
+ # getgroups is unprototyped.
+ ac_cv_type_getgroups=int
+ ], [
+ # Compiler caught incorrect argument list;
+ # gid_t is a typedef for int.
+ ac_cv_type_getgroups=gid_t
+ ])
+ ], [
+ # Both programs failed to compile - this probably means getgroups
+ # wasn't declared at all. Use 'int', as this is probably a very
+ # old system where the type _would have been_ int.
+ ac_cv_type_getgroups=int
+ ])
+ ])
+])dnl AC_CACHE_CHECK
AC_DEFINE_UNQUOTED(GETGROUPS_T, $ac_cv_type_getgroups,
- [Define to the type of elements in the array set by
+ [Define to the type of elements in the array argument to
'getgroups'. Usually this is either 'int' or 'gid_t'.])
])# AC_TYPE_GETGROUPS
diff --git a/tests/local.at b/tests/local.at
index 64a9fb264..db49f84a9 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -401,7 +401,7 @@ if test -f state-env.before && test -f state-env.after; then
[interpval|PATH_SEPARATOR],
[GFC|F77_DUMMY_MAIN|f77_(case|underscore)],
[FC(_DUMMY_MAIN|FLAGS|LIBS|FLAGS_[fF]|_MODEXT|_MODINC|_MODOUT|_DEFINE)?],
- [ALLOCA|GETLOADAVG_LIBS|KMEM_GROUP|NEED_SETGID|POW_LIB],
+ [ALLOCA|GETGROUPS_LIB|GETLOADAVG_LIBS|KMEM_GROUP|NEED_SETGID|POW_LIB],
[AWK|LEX|LEXLIB|LEX_OUTPUT_ROOT|LN_S|M4|MKDIR_P|AR|RANLIB|SET_MAKE|YACC],
[EGREP_TRADITIONAL],
[GREP|[EF]GREP|SED],
--
2.41.0