Skip to content

uniq, split: stop reading an obsolete option after -- - #14255

Open
arbelonson-source wants to merge 1 commit into
uutils:mainfrom
arbelonson-source:fix/uniq-split-obsolete-after-double-dash
Open

uniq, split: stop reading an obsolete option after --#14255
arbelonson-source wants to merge 1 commit into
uutils:mainfrom
arbelonson-source:fix/uniq-split-obsolete-after-double-dash

Conversation

@arbelonson-source

Copy link
Copy Markdown

uniq and split both walk the argument list before clap to lift out their obsolete numeric spellings — uniq -1 for skip-fields, split -22 for line count. Neither stopped at --, so an operand that merely looked like the obsolete form was swallowed instead of being treated as a file name.

Command GNU uutils before
uniq -- -1 uniq: -1: No such file or directory reads stdin, exits 0
split -- -1 split: cannot open '-1' for reading: No such file or directory reads stdin, exits 0

Found by differential testing against GNU coreutils 9.11.

Both walkers already threaded state for "the previous argument was an option expecting a value", so the terminator is tracked the same way: once -- is seen, everything after it is passed through untouched.

This is the same class of bug as #14248 (fold), but the three implementations are separate, so this is a separate change.

Testing

One regression test each. Verified they catch the bug by reverting the two source files alone — both fail, then pass with them restored.

  • cargo test --features "uniq,split" --no-default-features: 162 passed, 0 failed (160 pre-existing, 2 new)
  • cargo fmt --check and cargo clippy -p uu_uniq -p uu_split --all-targets: clean
  • split -- -1 now matches GNU byte for byte

Noted but not touched

The wording of uniq's own open failure still differs from GNU — uniq: Could not open -1: No such file or directory against GNU's uniq: -1: No such file or directory. That is unrelated to argument parsing: plain uniq nosuchfile differs the same way on an unmodified tree, which I checked before writing the test, so the test asserts only that -1 reaches the file layer.

fmt has the same -- problem (fmt -- -1 reads stdin where GNU tries to open -1), but it gets there differently — through a positional with allow_negative_numbers(true) rather than a pre-clap walk — so fixing it belongs in its own change rather than being bolted on here.

Disclosure

Prepared with AI assistance (Claude Code), per the AI policy in CONTRIBUTING.md. On the GPL point raised there: 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. All testing above was run locally.

Both walk the arguments before clap to lift out their obsolete numeric
spellings — `uniq -1` for skip-fields and `split -22` for line count.
Neither stopped at `--`, so an operand that merely looked like the
obsolete form was swallowed:

    $ uniq -- -1
    (reads stdin)        # GNU: uniq: -1: No such file or directory
    $ split -- -1
    (reads stdin)        # GNU: split: cannot open '-1' for reading

Track the terminator and pass everything after it through untouched.
Both walkers already tracked whether the previous argument was an
option expecting a value, so this is the same kind of state.

The wording of uniq's own open failure still differs from GNU
("Could not open -1" against "-1"), but that is unrelated: plain
`uniq nosuchfile` differs the same way on an unmodified tree.
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.

1 participant