Skip to content

unexpand: prevent overflow on over-large tab stop values - #14409

Open
zfaustk wants to merge 1 commit into
uutils:mainfrom
zfaustk:fix-unexpand-large-tabstop
Open

unexpand: prevent overflow on over-large tab stop values#14409
zfaustk wants to merge 1 commit into
uutils:mainfrom
zfaustk:fix-unexpand-large-tabstop

Conversation

@zfaustk

@zfaustk zfaustk commented Sep 6, 2026

Copy link
Copy Markdown

In write_tabs, tabstop target arithmetic previously added without overflow checks (print_state.scol + nts and print_state.scol + 1), causing debug builds with overflow checks to panic and release builds to wrap around when an over-large tabstop near usize::MAX is used. Furthermore, column tracking in unexpand_buf performed unguarded additions that could overflow if a character followed a large tab stop.

Use checked_add and saturating_add in write_tabs and unexpand_buf so over-large tab stop values are handled cleanly without panic or runaway loops, and add regression tests covering over-large tab stop arguments.

Fixes #14378

In write_tabs, tabstop target arithmetic previously added without overflow
checks, panicking in debug builds and wrapping in release builds when a
tabstop near usize::MAX is specified.

Use checked_add and saturating_add in write_tabs and column tracking so
over-large tabstops are handled cleanly without panic or runaway loops.
@codspeed-hq

codspeed-hq Bot commented Sep 6, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 15.31%

⚡ 2 improved benchmarks
✅ 2 untouched benchmarks
⏩ 414 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation unexpand_large_file[10] 286.2 ms 248.2 ms +15.33%
Simulation unexpand_many_lines[100000] 136.9 ms 118.7 ms +15.28%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing zfaustk:fix-unexpand-large-tabstop (3f6d698) with main (9ff4114)

Open in CodSpeed

Footnotes

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

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

GNU test failed: tests/tail/truncate. tests/tail/truncate is passing on 'main'. Maybe you have to rebase?
Skip an intermittent issue tests/cut/bounded-memory (fails in this run but passes 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-f is now passing!

// a tab, unless it's at the start of the line.
let ai = print_state.leading || amode;
if (ai && print_state.pctype != CharType::Tab && print_state.col > print_state.scol + 1)
if (ai

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.

this if is now too complex
could you please refactor it a bit ?

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.

unexpand: a plain over-large --tabs/-t value overflows (overflow-checks) or runs away (release) in the tab-conversion output path

2 participants