On 10/07/2026 15:18, h wrote:
Hello coreutils maintainers,
I sent this report four days ago, but it does not appear in the bug-coreutils
archive, so I am resending it after subscribing to the mailing list.
The details are provided below:
I noticed a possible robustness issue in GNU pr.
In src/pr.c, the -e tab width is parsed as an int, and very large positive
values are accepted. Later, when expanding tab characters, char_to_clump()
computes the tab expansion width and updates the current input position using
int arithmetic:
width = TAB_WIDTH(chars_per_input_tab, input_position);
...
input_position += width;
With a very large tab width and enough tab characters in the input, this
position update can exceed INT_MAX. In a normal build this may not produce a
visible failure, but with UBSan enabled it can report signed integer overflow.
For example, with a UBSan build:
printf '\t\t\t\t\t\t\t\t\t\n' > /tmp/tabs.txt
./src/pr -t -e268435456 /tmp/tabs.txt > /dev/null
This also implies very large memory allocation and output processing, since
clump_buff is allocated based on chars_per_input_tab.
I am not sure whether this should be considered a bug or just an extreme input
case.
I prepared a small patch for this issue.
The patch guards the input_position += width update in char_to_clump() with
ckd_add(),
so that an integer overflow is reported instead of relying on undefined signed
overflow behavior.
Please let me know if this approach looks reasonable.
Note: The patch author address is my other email address.
Best regards,
Guanqiang Han
Interestingly your repro triggers heap corruption
in the i18n patched version. I.e., on Fedora 44 I see:
$ valgrind pr -t -e268435456 tabs.txt > /dev/null
Invalid write of size 8
at 0x4864064: memset (vg_replace_strmem.c:1399)
by 0x4003CA9: char_to_clump_multi (pr.c:3010)
Note ckd_add doesn't need a temp variable,
and can operate directly on a single variable.
This should also have a test and NEWS,
which I've done in the proposed patch attached,
which I'll push soon.
Marking this as done.
thanks,
PadraigFrom 3b747e050574b0fe56689758bf570d527da81f04 Mon Sep 17 00:00:00 2001
From: Guanqiang Han <[email protected]>
Date: Tue, 7 Jul 2026 22:58:43 +0800
Subject: [PATCH] pr: guard input position update against overflow
* src/pr.c (char_to_clump): Use ckd_add() and report integer overflow.
* tests/pr/options.sh: Add a test case.
* NEWS: Mention the bug fix.
Fixes https://bugs.gnu.org/81393
---
NEWS | 4 ++++
src/pr.c | 5 ++++-
tests/pr/options.sh | 10 ++++++++++
3 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index 0e3d9bd5f..191d2ec63 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@ GNU coreutils NEWS -*- outline -*-
standard output is fully buffered, e.g., when redirected to a file.
[bug introduced in coreutils-9.10]
+ 'pr' now exits gracefully upon exceeding internal accounting limits,
+ like when processing large tab stops.
+ [This bug was present in "the beginning".]
+
'shred' no longer blocks when opening a FIFO that has no readers.
[This bug was present in "the beginning".]
diff --git a/src/pr.c b/src/pr.c
index 09a1b94a8..c3e085bcd 100644
--- a/src/pr.c
+++ b/src/pr.c
@@ -2732,7 +2732,10 @@ char_to_clump (char c)
else if (width < 0 && input_position <= -width)
input_position = 0;
else
- input_position += width;
+ {
+ if (ckd_add (&input_position, input_position, width))
+ integer_overflow ();
+ }
return chars;
}
diff --git a/tests/pr/options.sh b/tests/pr/options.sh
index feaf49f19..5d4d02cd1 100755
--- a/tests/pr/options.sh
+++ b/tests/pr/options.sh
@@ -57,4 +57,14 @@ printf '%s\n' "pr: '-e' extra characters or $INV in the argument: '-1'" \
>exp || framework_failure_
compare exp err || fail=1
+# Ensure we exit gracefully upon internal overflow limits
+# Tag as expensive as it uses little mem, but about 10s on a 2020 class machine.
+if test "$RUN_VERY_EXPENSIVE_TESTS" = yes ||
+ test "$RUN_EXPENSIVE_TESTS" = yes; then
+ head -c1M /dev/zero | tr '\0' '\t' |
+ returns_ 1 pr -t -e$(($INT_MAX/(1024*1024) + 1)) 2>err >/dev/null || fail=1
+ printf '%s\n' "pr: integer overflow" > exp || framework_failure_
+ compare exp err || fail=1
+fi
+
Exit $fail
--
2.55.0