coreutils icon indicating copy to clipboard operation
coreutils copied to clipboard

numfmt and printf with LONG_MIN and MAX

Open niyaznigmatullin opened this issue 2 years ago • 4 comments

This is the issue I want to discuss.

I tried to run gnu tests locally. It appeared that some tests use all the memory.

After some investigation it appeared that there are this tests:

  • numfmt --padding=-9223372036854775808 0
    

    So the test is actually

    ['pad-3.2', "--padding=$limits->{LONG_MIN} 0",
            {ERR => "$prog: invalid padding value '$limits->{LONG_MIN}'\n"},
            {EXIT => '1'}],
    

    this padding is unsupported in GNU version. And uutils version "supports" it, but probably not that I think that this use case with that large number bothers anyone. So GNU tests will fail, this will take many resources when running until all the memory is out, and also it's very slow if there is swap.

  • The same thing for other test cases

    printf %.*d 2147483648 15
    

    and

    printf %*d 2147483648 15
    

    which are

      ['d-big-prec', "%.*d $pow_2_31 15",  # INT_MAX
    {EXIT=>1}, {ERR=>"$prog: invalid precision: '$pow_2_31'\n"}],
      ['d-big-fwidth', "%*d $pow_2_31 15",  # INT_MAX
    {EXIT=>1}, {ERR=>"$prog: invalid field width: '$pow_2_31'\n"}],
    

What do you think, should we do?

  1. Just don't run them
  2. Change uutils version to handle the testcases as GNU does for these specific values
  3. Change uutils version to handle all big values as GNU does, not just these ones
  4. Somehow make a dummy preallocation of this size, to throw out memory exhausted error, and immediately free allocated memory. Somehow like that:
    { // this is done just for gnu tests to pass
        let mut v = vec![0u8; 1];
        v.try_reserve(implicit_padding.unwrap_or(options.padding).unsigned_abs())
            .map_err(|_| "memory exhausted")?
    }
    
    and change the tests to print the similar error. This will help to immediately raise an error, not wait until all memory comes out.

niyaznigmatullin avatar Aug 04 '22 15:08 niyaznigmatullin

If I understand correctly, GNU has some limits on the inputs they accept? I think that would be a good design decision, because if the padding is that large, it's very likely to be an error.

tertsdiepraam avatar Aug 04 '22 16:08 tertsdiepraam

I also like that solution. I will fix it then.

niyaznigmatullin avatar Aug 04 '22 18:08 niyaznigmatullin

Focusing just on numfmt, I checked GNU[1] and they check specifically for

padding_width < -LONG_MAX

So we could just do the same? Although it's probably some implementation-specific reason for them to check for it.

1: https://github.com/coreutils/coreutils/blob/master/src/numfmt.c#L1500

Edit: I figured it out. They flip the padding_width to positive if a negative integer is given. And since LONG_MIN = -LONG_MAX - 1, they can't flip the value if it is LONG_MIN. If we don't have this limitation, I suggest we disable the test.

tertsdiepraam avatar Aug 04 '22 21:08 tertsdiepraam

And for printf GNU version checks if INT_MIN <= width && width <= INT_MAX and uutils version store it in isize.

niyaznigmatullin avatar Aug 05 '22 08:08 niyaznigmatullin

Disabled tests in #3781

niyaznigmatullin avatar Aug 17 '22 10:08 niyaznigmatullin