I pushed this one after testing it on GNU/Linux, macOS, FreeBSD, and
NetBSD to confirm the memory limit wouldn't cause any trouble.

Thanks, Pádraig, for finding the version the bug was introduced in.

-- 8< --

Reported by Brian Foster in:
<https://bugs.launchpad.net/ubuntu/+source/coreutils/+bug/2161155>

* gnulib: Update to get commit b18879b9ed (canonicalize: Fix a missing
check for symlink loops., 2026-09-25)
* tests/misc/realpath.sh: Add a call to getlimits_. Add a test case.
* NEWS: Mention the bug fix.
---
 NEWS                   |  6 ++++++
 gnulib                 |  2 +-
 tests/misc/realpath.sh | 14 ++++++++++++++
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index d2fb7e7b3..4ba02413c 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@ GNU coreutils NEWS                                    -*- 
outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
+  'realpath' no longer loops infinitely when resolving a symbolic link which
+  resolves to a path beginning with the symbolic link itself.
+  [bug introduced in coreutils-9.0]
+
 ** New Features
 
   'env' and 'printenv' now support the --quoting-style option
diff --git a/gnulib b/gnulib
index 106e9b238..b18879b9e 160000
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit 106e9b2384d08a1696fcbd40cbab52237943f208
+Subproject commit b18879b9ed0df8a9539488022a128d9f89c83c18
diff --git a/tests/misc/realpath.sh b/tests/misc/realpath.sh
index 418ff2ffa..393ab1424 100755
--- a/tests/misc/realpath.sh
+++ b/tests/misc/realpath.sh
@@ -18,6 +18,7 @@
 
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ realpath
+getlimits_
 
 stat_single=$(stat -c %d:%i /) || framework_failure_
 stat_double=$(stat -c %d:%i //) || framework_failure_
@@ -134,4 +135,17 @@ mkdir noread && chmod a-r noread || framework_failure_
 test "$(realpath noread/)" = "$(realpath .)/noread" || fail=1
 test "$(realpath -e noread/)" = "$(realpath .)/noread" || fail=1
 
+# From coreutils 9.0 to 9.12, the following would loop until the
+# system ran out of memory.
+ln -s loop/a loop || framework_failure_
+vm=$(get_min_ulimit_v_ realpath .) && {
+  (ulimit -v $(($vm+6000)) &&
+     returns_ 1 timeout 10 realpath loop >out 2>err) || fail=1
+  cat <<EOF >exp || framework_failure_
+realpath: loop: $ELOOP
+EOF
+  compare /dev/null out || fail=1
+  compare exp err || fail=1
+}
+
 Exit $fail
-- 
2.55.0


Reply via email to