* src/seq.c (dump_strings): Rearrange limit checks to
reduce rounding affects. Also add sanity check on
on the iteration number limit.
* tests/seq/seq-no-progress.sh: Add a new test.
* tests/local.mk: Reference the new test.
* NEWS: Mention the fix.
Discovered by Anthropic's OSS Scanner, as bug ANT-2026-RI0OLUBX.
---
NEWS | 5 ++++
src/seq.c | 12 ++++++++-
tests/local.mk | 1 +
tests/seq/seq-no-progress.sh | 49 ++++++++++++++++++++++++++++++++++++
4 files changed, 66 insertions(+), 1 deletion(-)
create mode 100755 tests/seq/seq-no-progress.sh
diff --git a/NEWS b/NEWS
index aee2afea0..ff16b29a6 100644
--- a/NEWS
+++ b/NEWS
@@ -129,6 +129,11 @@ GNU coreutils NEWS -*-
outline -*-
resolves to a path beginning with the symbolic link itself.
[bug introduced in coreutils-9.0]
+ 'seq' no longer outputs the same number indefinitely when the increment
+ is too small to change the floating point value of FIRST.
+ For example with 'seq -w 1e40 1e40' or 'seq 1 1e-40 1'.
+ [This bug was present in "the beginning".]
+
'stty' again rejects empty speed arguments.
Previously such arguments were accepted as value 0.
[bug introduced in coreutils-9.8]
diff --git a/src/seq.c b/src/seq.c
index a49a18988..acae21fd0 100644
--- a/src/seq.c
+++ b/src/seq.c
@@ -313,12 +313,22 @@ print_numbers (char const *fmt, struct layout layout,
write_error ();
if (out_of_range)
break;
+ if (i + 1 == i)
+ error (EXIT_FAILURE, EOVERFLOW, _("sequence counter exhausted"));
/* Mathematically equivalent to 'x += step;', and typically
less subject to rounding error. */
x = first + i * step;
- out_of_range = (step < 0 ? x < last : last < x);
+ /* If STEP is too small to change X, then X might never pass LAST,
+ so compare the offsets from FIRST, which are not so rounded. */
+ if (x == x0
+ && ! (step < 0
+ ? last - first <= i * step : i * step <= last - first))
+ break;
+
+ /* Also treat NaN, from "seq -- -inf inf 0", as out of range. */
+ out_of_range = ! (step < 0 ? last <= x : x <= last);
if (out_of_range)
{
diff --git a/tests/local.mk b/tests/local.mk
index fbaaa653f..77cb83439 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -282,6 +282,7 @@ all_tests = \
tests/seq/seq-io-errors.sh \
tests/seq/seq-locale.sh \
tests/seq/seq-long-double.sh \
+ tests/seq/seq-no-progress.sh \
tests/seq/seq-precision.sh \
tests/head/head.pl \
tests/head/head-elide-tail.pl \
diff --git a/tests/seq/seq-no-progress.sh b/tests/seq/seq-no-progress.sh
new file mode 100755
index 000000000..da48dbb85
--- /dev/null
+++ b/tests/seq/seq-no-progress.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Ensure seq terminates when floating point arithmetic stops progressing.
+
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ seq
+
+# 2**130 is exactly representable in a 64 bit double
+big=1361129467683753853853498429727072845824
+test $(timeout 10 seq -f '%.0f' "$big" "$big" "$big") = "$big" ||
+ skip_ 'seq not built with double support'
+
+check_seq_ ()
+{
+ printf '%s\n' "$1" >exp || framework_failure_
+ shift
+
+ { timeout 10 seq "$@" 2>err; echo $? >status; } | head -n2 >out
+ echo 0 >exp-status || framework_failure_
+ compare exp-status status || fail=1
+ compare /dev/null err || fail=1
+ compare exp out || fail=1
+}
+
+check_seq_ "$big" -w "$big" "$big"
+check_seq_ "$big" "$big" 201 "$big"
+check_seq_ "-$big" -- "-$big" "-$big"
+check_seq_ "-$big" -- "-$big" -1 "-$big"
+
+check_seq_ 1.0000000000000000000000000000000000000000 1 1e-40 1
+check_seq_ -inf -- -inf -inf
+# Adding opposite infinities produces NaN, which must terminate the loop.
+check_seq_ -inf -- -inf inf 0
+
+Exit $fail
--
2.56.0