Skip to content

nl: reject line number width above INT_MAX instead of aborting - #13880

Open
AlejandroCoronadoN wants to merge 1 commit into
uutils:mainfrom
AlejandroCoronadoN:fix-nl-large-width-overflow
Open

nl: reject line number width above INT_MAX instead of aborting#13880
AlejandroCoronadoN wants to merge 1 commit into
uutils:mainfrom
AlejandroCoronadoN:fix-nl-large-width-overflow

Conversation

@AlejandroCoronadoN

Copy link
Copy Markdown

Summary

nl -w N accepts an arbitrarily large line-number field width and aborts with a
capacity overflow for very large values:

$ printf '\n' | nl -w 9223372036854775807
thread 'main' panicked at library/alloc/src/slice.rs: capacity overflow
Aborted (core dumped)
$ echo $?
134

Root cause

The width is only checked for > 0. A large width then reaches
" ".repeat(number_width + 1), which aborts when the requested capacity exceeds
isize::MAX.

Fix

Match GNU, which bounds -w to a C int ([1, INT_MAX]): reject a width above
i32::MAX up front with the existing "invalid line number field width" error
(exit 1) instead of aborting. Widths up to i32::MAX are still accepted, as in
GNU. Adds a regression test.

$ printf '\n' | nl -w 2147483648   # INT_MAX + 1
nl: Invalid line number field width: '2147483648': Numerical result out of range
$ echo $?
1

Fixes #13347.

@codspeed-hq

codspeed-hq Bot commented Aug 11, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 3.37%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 344 untouched benchmarks
⏩ 46 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation df_with_path 573.7 µs 704.6 µs -18.58%
Simulation du_max_depth_balanced_tree[(6, 4, 10)] 65.2 ms 61.8 ms +5.43%
Simulation du_summarize_balanced_tree[(5, 4, 10)] 16.8 ms 16 ms +5.09%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing AlejandroCoronadoN:fix-nl-large-width-overflow (577daa5) with main (822aa83)

Open in CodSpeed

Footnotes

  1. 46 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.

@github-actions

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/cut/bounded-memory (fails in this run but passes in the 'main' branch)
Skip an intermittent issue tests/date/date-locale-hour (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/date/resolution (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/tail/symlink (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/tail/tail-n0f (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/tail/pipe-f2 is no longer failing!
Note: The gnu test tests/printf/printf-surprise is now being skipped but was previously passing.

Comment thread src/uu/nl/src/helper.rs Outdated
// `" ".repeat(number_width + 1)` abort with a capacity overflow.
Some(num) if *num > i32::MAX as usize => {
errs.push(translate!("nl-error-invalid-line-width", "value" => num.to_string()));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reject it by clap's value_parser instead.

@AlejandroCoronadoN

Copy link
Copy Markdown
Author

Thanks for the review! Done: I moved the bound to clap's value_parser (range(..=i32::MAX as u64)) instead of the manual check, so a width above INT_MAX is now rejected at parse time. The zero case keeps its existing GNU-style message. Force-pushed.

Per review feedback, bound -w with clap value_parser to match GNU's C int
limit instead of a manual check, so a huge width is rejected at parse time
rather than aborting later with a capacity overflow. Adds a regression test.

Fixes uutils#13347.
Comment thread src/uu/nl/src/nl.rs
// Bound the width to a C int like GNU. This rejects a huge width
// up front instead of letting a later `" ".repeat(width + 1)`
// abort with a capacity overflow (#13347).
.value_parser(clap::value_parser!(u64).range(..=i32::MAX as u64)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.value_parser(clap::value_parser!(u64).range(..=i32::MAX as u64)),
.value_parser(clap::value_parser!(u64).range(1..=i32::MAX as u64)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't make stderr 100% same with GNU too.

Comment thread src/uu/nl/src/nl.rs
.value_parser(clap::value_parser!(usize)),
// Bound the width to a C int like GNU. This rejects a huge width
// up front instead of letting a later `" ".repeat(width + 1)`
// abort with a capacity overflow (#13347).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If test is added already, the comment is unnecessary.

Comment thread tests/by-util/test_nl.rs
.args(&["-w", "2147483648"])
.pipe_in("x\n")
.fails()
.stderr_contains("is not in 0..=2147483647");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would drop .stderr_contains and kep fails only since it is clap's message instead of GNU's one.

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.

nl: capacity-overflow abort on a large -w/--number-width

2 participants