On 28/12/2022 13:49, наб wrote:
Control: retitle -1 coreutils: wc: -c st_size optimisation broken for files 
larger than max(size_t)

Hi!

On Wed, Dec 28, 2022 at 01:31:12PM +0000, Pádraig Brady wrote:
On 27/12/2022 19:38, наб wrote:
To repro this, run truncate -s 2E a, then wc -c a;
this completes instantly on bullseye and spins in a read(2) loop on sid.
I think I see the issue but only on 32 bit size_t.
Ah this is x32, as per your report.

The patch doesn't apply to the Debian source unfortunately, but
I can confirm this behaves as you'd expect for a [iu]64->u32 truncation:
-- >8 --
$ truncate -s $(echo 2^32-1 | bc) a
$ time wc -c a
4294967295 a

real    0m0.002s
user    0m0.002s
sys     0m0.000s
$ truncate -s $(echo 2^32 | bc) a
$ time wc -c a
4294967296 a

real    0m0.718s
user    0m0.092s
sys     0m0.626s
-- >8 --

And I can repro this exact behaviour on i386.

Proposed upstream patch attached.

thanks,
Pádraig
From be259a269bee563e4670c5936efb9031835525ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Wed, 28 Dec 2022 14:04:19 +0000
Subject: [PATCH] wc: fix regression determining file size

* src/wc.c (wc): Use off_t rather than size_t
when calculating where to seek to, so that
we don't seek to a too low offset on systems
where size_t < off_t, which would result in
many read() calls to determine the file size.
* tests/misc/wc-proc.sh: Add a test case
sufficient for 32 bit systems at least.
Reported at https://bugs.debian.org/1027101
---
 src/wc.c              | 2 +-
 tests/misc/wc-proc.sh | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/wc.c b/src/wc.c
index bc52a8c0e..df9770396 100644
--- a/src/wc.c
+++ b/src/wc.c
@@ -431,7 +431,7 @@ wc (int fd, char const *file_x, struct fstatus *fstatus, off_t current_pos)
       if (! fstatus->failed && usable_st_size (&fstatus->st)
           && 0 <= fstatus->st.st_size)
         {
-          size_t end_pos = fstatus->st.st_size;
+          off_t end_pos = fstatus->st.st_size;
           if (current_pos < 0)
             current_pos = lseek (fd, 0, SEEK_CUR);
 
diff --git a/tests/misc/wc-proc.sh b/tests/misc/wc-proc.sh
index 581890ddd..030872a91 100755
--- a/tests/misc/wc-proc.sh
+++ b/tests/misc/wc-proc.sh
@@ -42,4 +42,11 @@ cat <<\EOF > exp
 EOF
 compare exp out || fail=1
 
+# Ensure we don't read too much when reading,
+# as was the case on 32 bit systems
+# from coreutils-8.24 to coreutils-9.1
+if timeout 10 truncate -s1T do_read; then
+  timeout 10 wc -c do_read || fail=1
+fi
+
 Exit $fail
-- 
2.26.2

Reply via email to