* src/split.c (lines_chunk_split): Make sure CHUNK_NO does not exceed N.
* tests/split/l-chunk.sh: Add a test case without --elide-empty-files
and with it.
* NEWS: Mention the bug fix.
Discovered by Anthropic's OSS Scanner, as bug ANT-2026-ZDDBFXXM.
---
NEWS | 6 ++++++
src/split.c | 2 +-
tests/split/l-chunk.sh | 33 +++++++++++++++++++++++++++++++++
3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index d932371d7..e3a23fe54 100644
--- a/NEWS
+++ b/NEWS
@@ -195,6 +195,12 @@ GNU coreutils NEWS -*-
outline -*-
alphabet, giving arbitrary and repeated file names, thus losing output.
[bug introduced with the --hex-suffixes option in coreutils-8.28]
+ 'split --number=l/N' no longer creates more than N output files,
+ truncating them if they exist, or loops infinitely when used with
+ --elide-empty-files, when the input is smaller than N bytes and ends
+ with a newline.
+ [bug introduced in coreutils-9.2]
+
'stty' again rejects empty speed arguments.
Previously such arguments were accepted as value 0.
[bug introduced in coreutils-9.8]
diff --git a/src/split.c b/src/split.c
index da30b109d..71a097264 100644
--- a/src/split.c
+++ b/src/split.c
@@ -1052,7 +1052,7 @@ lines_chunk_split (intmax_t k, intmax_t n, char *buf,
idx_t bufsize,
return;
chunk_end += chunk_size + (chunk_no < rem_bytes);
chunk_no++;
- if (chunk_end <= n_written)
+ if (chunk_no <= n && chunk_end <= n_written)
{
if (! k)
cwrite (true, NULL, 0);
diff --git a/tests/split/l-chunk.sh b/tests/split/l-chunk.sh
index d79ed9b00..d1b072654 100755
--- a/tests/split/l-chunk.sh
+++ b/tests/split/l-chunk.sh
@@ -126,4 +126,37 @@ printf '5' > exp
split -n l/7/7 in > out
compare exp out || fail=1
+# In coreutils-9.2 through coreutils-9.12, this would exit with a failure
+# upon exhausting output files, overwriting them if they exist.
+printf 'a\n' >in &&
+printf 'b\n' >out.af &&
+cp out.af exp-out.af &&
+truncate -s 0 exp || framework_failure_
+split -n l/5 in out. >out 2>err || fail=1
+compare /dev/null out || fail=1
+compare /dev/null err || fail=1
+set -- out.*
+files="$*"
+exp_files='out.aa out.ab out.ac out.ad out.ae out.af'
+test "$files" = "$exp_files" || fail=1
+for file in $exp_files; do
+ exp=exp
+ if test $file = out.aa; then
+ exp=in
+ elif test $file = out.af; then
+ exp=exp-out.af
+ fi
+ compare $exp $file || fail=1
+done
+rm -f $exp_files || framework_failure_
+
+# In coreutils-9.2 through coreutils-9.12, this would loop infinitely.
+printf 'a\n' >in || fail=1
+timeout 10 split -e -n l/5 in out. >out 2>err || fail=1
+compare /dev/null out || fail=1
+compare /dev/null err || fail=1
+set -- out.*
+test "$*" = out.aa || fail=1
+compare in out.aa || fail=1
+
Exit $fail
--
2.56.0