head, tail: reject multiplier suffixes that GNU rejects - #14228
head, tail: reject multiplier suffixes that GNU rejects#14228kennywillbe wants to merge 5 commits into
Conversation
The count argument of head and tail is parsed with the generic size parser, which accepts a lowercase form of every multiplier. GNU only accepts a lowercase 'k' and 'm', so 2g, 2t, 2p, 2e, 2z, 2y, 2r and 2q were silently accepted instead of being reported as invalid. Restrict the shared parser to the suffixes these utilities accept: k, m, K, M, G, T, P, E, Z, Y, R and Q, each also valid followed by B, iB or D, plus a bare b.
/dev/null does not exist on Windows and is not visible inside the WASI sandbox, so the accepted-suffix test failed on those targets. Feed the input through stdin, as the matching tail tests already do.
|
GNU testsuite comparison: |
The test only needs to show that these suffixes parse, and asserting the copied bytes makes it fail on 32-bit targets, where uucore's splice path truncates the byte count.
Merging this PR will improve performance by 3.04%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | du_deep_tree[(100, 3)] |
2.1 ms | 2 ms | +3.04% |
Tip
Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.
Comparing kennywillbe:tail-head-gnu-suffixes (dbe4ef1) with main (c4c2fd0)2
Footnotes
-
50 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
-
No successful run was found on
main(594dc6a) during the generation of this report, so c4c2fd0 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩
Fixes #13136.
headandtailparse their count argument throughparse_signed_num_max, which uses the generic size parser with no allow list. That parser accepts a lowercase form of every multiplier, so2g,2t,2p,2e,2z,2y,2rand2qwere silently accepted:GNU reports
invalid number of bytes: '2z'for all of these. It accepts a lowercase suffix only forkandm.This restricts the shared parser to the set both utilities accept:
k m K M G T P E Z Y R Q, each also valid followed byB,iBorD, plus a bareb(which has noB/iB/Dform).headandtailtake the same set, so one allow list covers both.I derived the set by running GNU coreutils 9.11 and comparing, not from its source. After the change I diffed every letter of the alphabet in all four forms (
X,XB,XiB,XD) for-con both utilities, 208 combinations, and every-ncombination with a+/-prefix: no remaining differences.Tests added to
test_head.rsandtest_tail.rscover both the newly rejected suffixes and the accepted ones, for-cand-n, so a regression in either direction fails.One thing left out deliberately: with a leading zero the error names the trimmed string, so
tail -c0gsaysinvalid number of bytes: 'g'where GNU says'0g'. That is pre-existing (tail -c0fbmisreports the same way today) and unrelated to the suffix set, so I will report it separately.