Skip to content

head, tail: keep leading zeros in an invalid count message - #14249

Open
arbelonson-source wants to merge 1 commit into
uutils:mainfrom
arbelonson-source:fix/14229-leading-zeros-in-count-error
Open

head, tail: keep leading zeros in an invalid count message#14249
arbelonson-source wants to merge 1 commit into
uutils:mainfrom
arbelonson-source:fix/14229-leading-zeros-in-count-error

Conversation

@arbelonson-source

Copy link
Copy Markdown

Closes #14229.

parse_signed_num_max strips leading zeros so the count is read as decimal rather than octal, then hands the trimmed string to the size parser. The error carries that trimmed string, so the zeros the user typed never reach the message.

Command GNU uutils before
tail -c0fb a invalid number of bytes: '0fb' invalid number of bytes: 'fb'
tail -c00x a invalid number of bytes: '00x' invalid number of bytes: 'x'
head -n0x a invalid number of lines: '0x' invalid number of lines: 'x'
tail -c-0fb a invalid number of bytes: '0fb' invalid number of bytes: 'fb'

The error is now rebuilt around the untrimmed operand. Only the two variants that carry the operand and nothing else are rebuilt — SizeTooBig also carries an explanation after it and PhysicalMem is not about the operand at all. Neither can arise on this path anyway, since parse_size_u64_max clamps rather than overflowing.

The sign stays stripped, matching GNU, which reports the operand of tail -c-0fb as '0fb'.

Worth noting: this also lines the message up with number_offset, which already counts leading zeros as part of the number when placing the caret — its existing test says "The parser reads leading zeros as part of the number, so they stay", which was not true of the message until now.

Testing

Two unit tests on the parser and one integration test each for head and tail. I verified they catch the bug by reverting the two map_err calls alone — the parser tests fail, then pass again once restored.

  • cargo test -p uucore --features parser: 195 passed, 0 failed
  • cargo test --features "head,tail" --no-default-features: 222 passed, 0 failed (220 pre-existing, 2 new)
  • cargo fmt --check and cargo clippy -p uucore -p uu_head -p uu_tail --all-targets: clean
  • 34-case differential sweep of head/tail count arguments against GNU coreutils 9.11: all 34 now match, including the valid cases (-c007, -n07, -c1K) as regression cover

One thing I found but did not fix

While sweeping, tail -c007z and head -n0000q succeed where GNU rejects them — uutils accepts lowercase unit suffixes that GNU does not. That is the suffix question in #13136 rather than this one, so I left it alone and deliberately kept those spellings out of the tests here so the two do not become entangled.

Disclosure

Prepared with AI assistance (Claude Code), per the AI policy in CONTRIBUTING.md. On the GPL point raised there: the expected behavior was established by running the installed GNU binaries as a black box and recording their output. I did not read GNU coreutils source while writing this. All testing above was run locally.

Closes uutils#14229.

`parse_signed_num_max` strips leading zeros so the count is read as
decimal rather than octal, then hands the trimmed string to the size
parser. The error carries that trimmed string, so the zeros the user
typed never reach the message:

    $ tail -c0fb a
    tail: invalid number of bytes: 'fb'      # GNU: '0fb'
    $ head -n0x a
    head: invalid number of lines: 'x'       # GNU: '0x'

Rebuild the error around the untrimmed operand instead. Only the two
variants that carry the operand alone are rebuilt; `SizeTooBig` also
carries an explanation and `PhysicalMem` is not about the operand, and
neither can arise here anyway, since `parse_size_u64_max` clamps rather
than overflowing.

The sign stays stripped, matching GNU, which reports the operand of
`tail -c-0fb` as '0fb'. This also lines the message up with
`number_offset`, which already counts leading zeros as part of the
number when placing the caret.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

head, tail: an invalid count with a leading zero is reported without the leading zeros

1 participant