Merge into lib/canonicalize-lgpl.c the changes of glibc
stdlib/canonicalize.c through glibc commit
b589bd672c529cf264dc6dfdfa11f73c7e4e1666 dated today.
The result should be copiable back to glibc byte-for-byte.
The original motivation for this merge was to make
eloop-threshold.h thread-safe on all platforms.
It turned out that glibc has already done this, trivially,
by having the include file define a constant 40 rather than a function.
This conforms to POSIX on all glibc targets, and it should also
work on all Gnulib targets that I know of,
as sysconf (_SC_SYMLOOP_MAX) <= 40 on all known platforms.
POSIX allows us to follow more symlink expansions than
any nonnegative number returned by sysconf (_SC_SYMLOOP_MAX),
and if that number is negative POSIX requires only to expand
at least 8 symlinks so the glibc value of 40 is good then too.
* NEWS: Mention the incompatible change.
* config/srclist.txt: Add lib/min-eloop-threshold.h.
* lib/canonicalize-lgpl.c [_LIBC]: Include <stdbool.h>.
(__rawmemchr): Remove. Replace its use with strchr.
* lib/min-eloop-threshold.h: Sync byte-for-byte from gnulibc,
renaming the file from lib/eloop-threshold.h. All uses changed.
This entails the following changes:
(_MIN_ELOOP_THRESHOLD_H): Rename from _ELOOP_THRESHOLD_H.
All uses changed.
Don’t #error out if config.h is not already included.
Don’t include <limits.h>.
[_LIBC]: Don’t include <sys/param.h>.
(_GL_ATTRIBUTE_CONST) [_LIBC]: Remove.
[!_LIBC]: Don’t include <unistd.h>, "minmax.h".
(__sysconf, SYMLOOP_MAX) [!_LIBC]: Remove.
(MIN_ELOOP_THRESHOLD): Define unconditionally.
(__eloop_threshold): Remove. All uses replaced by MIN_ELOOP_THRESHOLD.
The new expression is of type int not unsigned, but that’s better
for callers anyway.
* lib/openat2.c (do_openat2): Symlink count is now int, not long int.
* modules/eloop-threshold (Files, Include): Adjust to file name change.
(Depends-on): Remove minmax, unistd-h.
+2026-08-10 Paul Eggert <eggert@cs.ucla.edu>
+
+ canonicalize-lgpl: sync from glibc
+ Merge into lib/canonicalize-lgpl.c the changes of glibc
+ stdlib/canonicalize.c through glibc commit
+ b589bd672c529cf264dc6dfdfa11f73c7e4e1666 dated today.
+ The result should be copiable back to glibc byte-for-byte.
+ The original motivation for this merge was to make
+ eloop-threshold.h thread-safe on all platforms.
+ It turned out that glibc has already done this, trivially,
+ by having the include file define a constant 40 rather than a function.
+ This conforms to POSIX on all glibc targets, and it should also
+ work on all Gnulib targets that I know of,
+ as sysconf (_SC_SYMLOOP_MAX) <= 40 on all known platforms.
+ POSIX allows us to follow more symlink expansions than
+ any nonnegative number returned by sysconf (_SC_SYMLOOP_MAX),
+ and if that number is negative POSIX requires only to expand
+ at least 8 symlinks so the glibc value of 40 is good then too.
+ * NEWS: Mention the incompatible change.
+ * config/srclist.txt: Add lib/min-eloop-threshold.h.
+ * lib/canonicalize-lgpl.c [_LIBC]: Include <stdbool.h>.
+ (__rawmemchr): Remove. Replace its use with strchr.
+ * lib/min-eloop-threshold.h: Sync byte-for-byte from gnulibc,
+ renaming the file from lib/eloop-threshold.h. All uses changed.
+ This entails the following changes:
+ (_MIN_ELOOP_THRESHOLD_H): Rename from _ELOOP_THRESHOLD_H.
+ All uses changed.
+ Don’t #error out if config.h is not already included.
+ Don’t include <limits.h>.
+ [_LIBC]: Don’t include <sys/param.h>.
+ (_GL_ATTRIBUTE_CONST) [_LIBC]: Remove.
+ [!_LIBC]: Don’t include <unistd.h>, "minmax.h".
+ (__sysconf, SYMLOOP_MAX) [!_LIBC]: Remove.
+ (MIN_ELOOP_THRESHOLD): Define unconditionally.
+ (__eloop_threshold): Remove. All uses replaced by MIN_ELOOP_THRESHOLD.
+ The new expression is of type int not unsigned, but that’s better
+ for callers anyway.
+ * lib/openat2.c (do_openat2): Symlink count is now int, not long int.
+ * modules/eloop-threshold (Files, Include): Adjust to file name change.
+ (Depends-on): Remove minmax, unistd-h.
+
2026-08-09 Paul Eggert <eggert@cs.ucla.edu>
hamt: port to non-_Atomic C platforms
Date Modules Changes
+2026-08-10 eloop-threshold Now include <min-eloop-threshold.h> and use
+ MIN_ELOOP_THRESHOLD rather than including
+ <eloop-threshold.h> and using __eloop_threshold ().
+
2026-06-26 bitrotate This module is deprecated. Use stdc_rotate_left
or stdc_rotate_right instead.
$LIBCSRC stdlib/tst-stdc_leading_zeros.c tests/from-glibc
$LIBCSRC stdlib/tst-stdc_trailing_ones.c tests/from-glibc
$LIBCSRC stdlib/tst-stdc_trailing_zeros.c tests/from-glibc
-#$LIBCSRC sysdeps/generic/eloop-threshold.h lib
+$LIBCSRC sysdeps/generic/min-eloop-threshold.h lib
#$LIBCSRC time/timegm.c lib
#$LIBCSRC time/mktime.c lib
#$LIBCSRC time/mktime-internal.h lib
#include <sys/stat.h>
#include <unistd.h>
-#include <eloop-threshold.h>
+#include <min-eloop-threshold.h>
#include <filename.h>
#include <idx.h>
#include <intprops.h>
#ifdef _LIBC
# include <shlib-compat.h>
+# include <stdbool.h>
# define GCC_LINT 1
# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
#else
# endif
# define __mempcpy mempcpy
# define __pathconf pathconf
-# define __rawmemchr rawmemchr
# define __readlink readlink
# if IN_RELOCWRAPPER
/* When building the relocatable program wrapper, use the system's memmove
return NULL;
rname = bufs->rname.data;
}
- dest = __rawmemchr (rname, '\0');
+ dest = strchr (rname, '\0');
start = name;
prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
}
}
if (0 <= n)
{
- if (++num_links > __eloop_threshold ())
+ if (++num_links > MIN_ELOOP_THRESHOLD)
{
__set_errno (ELOOP);
goto error;
+++ /dev/null
-/* Threshold at which to diagnose ELOOP. Generic version.
- Copyright (C) 2012-2026 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-#ifndef _ELOOP_THRESHOLD_H
-#define _ELOOP_THRESHOLD_H 1
-
-/* This file uses _GL_ATTRIBUTE_CONST. */
-#if !_LIBC && !_GL_CONFIG_H_INCLUDED
- #error "Please include config.h first."
-#endif
-
-#include <limits.h>
-#ifdef _LIBC
-# include <sys/param.h>
-# define _GL_ATTRIBUTE_CONST __attribute__ ((const))
-#else
-# include <unistd.h>
-# include "minmax.h"
-# define __sysconf sysconf
-# if (!defined SYMLOOP_MAX \
- && ! (defined _SC_SYMLOOP_MAX && defined _POSIX_SYMLOOP_MAX))
-# define SYMLOOP_MAX 8
-# endif
-#endif
-
-/* POSIX specifies SYMLOOP_MAX as the "Maximum number of symbolic
- links that can be reliably traversed in the resolution of a
- pathname in the absence of a loop." This makes it a minimum that
- we should certainly accept. But it leaves open the possibility
- that more might sometimes work--just not "reliably".
-
- For example, Linux implements a complex policy whereby there is a
- small limit on the number of direct symlink traversals (a symlink
- to a symlink to a symlink), but larger limit on the total number of
- symlink traversals overall. Hence the SYMLOOP_MAX number should be
- the small one, but the limit library functions enforce on users
- should be the larger one.
-
- So, we use the larger of the reported SYMLOOP_MAX (if any) and our
- own constant MIN_ELOOP_THRESHOLD, below. This constant should be
- large enough that it never rules out a file name and directory tree
- that the underlying system (i.e. calls to 'open' et al) would
- resolve successfully. It should be small enough that actual loops
- are detected without a huge number of iterations. */
-
-#ifndef MIN_ELOOP_THRESHOLD
-# define MIN_ELOOP_THRESHOLD 40
-#endif
-
-/* Return the maximum number of symlink traversals to permit
- before diagnosing ELOOP. */
-static inline unsigned int _GL_ATTRIBUTE_CONST
-__eloop_threshold (void)
-{
-#ifdef SYMLOOP_MAX
- const int symloop_max = SYMLOOP_MAX;
-#else
- /* The function is marked 'const' even though we use memory and
- call a function, because sysconf is required to return the
- same value in every call and so it must always be safe to
- call __eloop_threshold exactly once and reuse the value. */
- static long int sysconf_symloop_max;
- if (sysconf_symloop_max == 0)
- sysconf_symloop_max = __sysconf (_SC_SYMLOOP_MAX);
- const unsigned int symloop_max = (sysconf_symloop_max <= 0
- ? _POSIX_SYMLOOP_MAX
- : sysconf_symloop_max);
-#endif
-
- return MAX (symloop_max, MIN_ELOOP_THRESHOLD);
-}
-
-#endif /* eloop-threshold.h */
#include "areadlink.h"
#include "dirname.h"
-#include "eloop-threshold.h"
#include "filenamecat.h"
+#include "min-eloop-threshold.h"
#include "openat-priv.h"
#if !HAVE_LINKAT || LINKAT_SYMLINK_NOTSUP
{
char *name = (char *) file1;
char *target;
- int i = __eloop_threshold ();
+ int i = MIN_ELOOP_THRESHOLD;
/* Using realpath or canonicalize_file_name is too heavy-handed: we
don't need an absolute name, and we don't need to resolve
{
char *name = (char *) file1;
char *target;
- int i = __eloop_threshold ();
+ int i = MIN_ELOOP_THRESHOLD;
/* There is no realpathat. */
while (i-- && (target = areadlinkat (fd1, name)))
--- /dev/null
+/* Minimum threshold at which to diagnose ELOOP. Generic version.
+ Copyright (C) 2012-2026 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _MIN_ELOOP_THRESHOLD_H
+#define _MIN_ELOOP_THRESHOLD_H 1
+
+/* POSIX specifies SYMLOOP_MAX as the "Maximum number of symbolic
+ links that can be reliably traversed in the resolution of a
+ pathname in the absence of a loop." This makes it a minimum that
+ we should certainly accept. But it leaves open the possibility
+ that more might sometimes work--just not "reliably".
+
+ For example, Linux implements a complex policy whereby there is a
+ small limit on the number of direct symlink traversals (a symlink
+ to a symlink to a symlink), but larger limit on the total number of
+ symlink traversals overall. Hence the SYMLOOP_MAX number should be
+ the small one, but the limit library functions enforce on users
+ should be the larger one.
+
+ This constant should be large enough that it never rules out a file
+ name and directory tree that the underlying system (i.e. calls to 'open'
+ et al) would resolve successfully. It should be small enough that
+ actual loops are detected without a huge number of iterations. */
+
+#define MIN_ELOOP_THRESHOLD 40
+
+#endif
#include <fcntl.h>
-#include "eloop-threshold.h"
#include "filename.h"
#include "ialloc.h"
#include "idx.h"
+#include "min-eloop-threshold.h"
#include "verify.h"
#include <errno.h>
dev_t const UNKNOWN_DEV = -1;
dev_t ddev = UNKNOWN_DEV;
- long int maxlinks = resolve & RESOLVE_NO_SYMLINKS ? 0 : __eloop_threshold ();
+ int maxlinks = resolve & RESOLVE_NO_SYMLINKS ? 0 : MIN_ELOOP_THRESHOLD;
int dfd = *fd;
Threshold for symbolic link loops and ELOOP
Files:
-lib/eloop-threshold.h
+lib/min-eloop-threshold.h
Depends-on:
-minmax
-unistd-h
configure.ac:
Makefile.am:
Include:
-<eloop-threshold.h>
+<min-eloop-threshold.h>
License:
LGPLv2+