Subject: Re: bug#13530: head: memory exhausted when printing all from stdin but last P/E bytes

From: Jim Meyering <[email-masked]>
Date: Sun, 02 Jun 2013 05:46:53 +0200

Pádraig Brady wrote:
...
>> +# Use a limit of N = SIZE_MAX - max_BUFSIZ
>> +# The "- max_BUFSIZ" term is because head must be able to add BUFSIZ
>> +# to the selected value of N without exceeding SIZE_MAX.
>> +# Since we've seen BUFSIZ up to 128K, use 256K to be safe.
>> +max_BUFSIZ=$(expr 256 '*' 1024)
>> +
>> +# It's ok to use a 10-digit $SIZE_MAX, because expr uses wider intmax_t.
>> +# However, when $SIZE_MAX is longer, it's a 20-digit quantity that is
>> +# too large for GMP-disabled expr to handle, so use $SSIZE_MAX there.
>> +# We'd use $SSIZE_MAX in both cases, but want to keep the number as
>> +# large as possible for the 32-bit case, since there, it may barely
>> +# exceed the size of available RAM, while SSIZE_MAX probably will not.
>> +test $(printf $SIZE_MAX|wc -c) -lt 11 \
>> +  && big=$SIZE_MAX \
>> +  || big=$SSIZE_MAX
>> +
>> +lim=$(expr $big - $max_BUFSIZ) \
>
> trailing \ is not needed.
>
> The above assumes intmax_t is always wider than size_t,
> which is might be OK?
> Also since OFF_T_MAX is checked earlier in the code,
> it assumes that off_t is wider than size_t which isn't
> the case if _FILE_OFFSET_BITS is not 64.
>
> You could take the approach to just use $SSIZE_MAX,
> and assume 64 bit testing covers the 32 bit case implicitly?
> That would also assume that off_t was never narrower than size_t,
> but that's probably OK.
>
> These limits are painful. Sorry for the churn :(

This started because the test passed on 64-bit, yet failed on 32-bit.
If it were to use $SSIZE_MAX, the test could mistakenly pass when
run without the underlying patch, because on a 32-bit system,
it's not uncommon to have 2^31 bytes of RAM, so the allocation
could succeed.

However, that's so much simpler that I now think it's the way to go.
Thanks!

>From aeaeb87c134ce748527ba99e749b7369fcba2438 Mon Sep 17 00:00:00 2001
From: Jim Meyering <[email-masked]>
Date: Mon, 27 May 2013 17:01:14 -0700
Subject: [PATCH] tests: head-c: avoid spurious failure with a 32-bit size_t

* tests/misc/head-c.sh: Don't try to elide 1 exabytes, since on
32-bit systems, that number is not representable as a size_t.
This command would fail on 32-bit systems, where SIZE_MAX < 1E:
  head --bytes=-E < /dev/null
Instead of "E", use $SSIZE_MAX.
For discussion, see http://bugs.gnu.org/13530
---
 tests/misc/head-c.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/misc/head-c.sh b/tests/misc/head-c.sh
index 37a86ce..a5b6c6a 100755
--- a/tests/misc/head-c.sh
+++ b/tests/misc/head-c.sh
@@ -19,6 +19,7 @@
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ head
 require_ulimit_v_
+getlimits_

 # exercise the fix of 2001-08-18, based on test case from Ian Bruce
 echo abc > in || framework_failure_
@@ -31,6 +32,6 @@ esac
 # Only allocate memory as needed.
 # Coreutils <= 8.21 would allocate memory up front
 # based on the value passed to -c
-(ulimit -v 20000; head --bytes=-E < /dev/null) || fail=1
+(ulimit -v 20000; head --bytes=-$SSIZE_MAX < /dev/null) || fail=1

 Exit $fail
--
1.8.3.101.g727a46b