Skip to content

Fix usize underflow panic with wide chars at --terminal-width 1 - #3875

Open
koopatroopa787 wants to merge 2 commits into
sharkdp:masterfrom
koopatroopa787:fix-wide-char-cursor-underflow
Open

Fix usize underflow panic with wide chars at --terminal-width 1#3875
koopatroopa787 wants to merge 2 commits into
sharkdp:masterfrom
koopatroopa787:fix-wide-char-cursor-underflow

Conversation

@koopatroopa787

Copy link
Copy Markdown

Summary

bat --terminal-width 1 --wrap character aborted with capacity overflow (exit 101) when a line contained a double-width character (CJK/emoji) and a background was painted on that line:

$ printf '📦📦\n' | bat --highlight-line 1 --terminal-width 1 --wrap character \
                       --color always --paging never --theme OneHalfDark
thread 'main' panicked at library/alloc/src/slice.rs:524:23:
capacity overflow
$ echo $?
101

Root Cause

cursor accumulates the display width of each chunk. With --terminal-width 1, cursor_max = 1. A double-width character (display width 2) makes cursor = 2 > cursor_max = 1.

Two sites then performed unchecked cursor_max - cursor subtraction:

  • printer.rs:822: let mut max_width = cursor_max - cursor; — used to size the text chunk buffer
  • printer.rs:934: " ".repeat(cursor_max - cursor) — used to fill the end-of-line background

Both wrap to ~usize::MAX, and " ".repeat(~usize::MAX) aborts with capacity overflow.

(This is the same defect class as the --style=snip width-1 panic in #3803.)

Fix

Use saturating_sub at both sites so an overshot cursor yields a fill/buffer width of 0, matching the guard already applied at printer.rs:789.

Fixes #3844

`--line-range :-N` with N near usize::MAX aborted with "capacity
overflow" in two ways:

1. `largest_offset_from_end() + 1` overflowed usize when N == usize::MAX.
2. `VecDeque::with_capacity(usize::MAX)` panicked with capacity overflow.

Replace the plain `+ 1` with `saturating_add(1)` and the infallible
`VecDeque::with_capacity` with `try_reserve`, so an impossibly large
offset produces a clear error message instead of an abort.

Fixes sharkdp#3845
When `--terminal-width 1` is combined with `--wrap character` and a line
contains a character whose display width exceeds the terminal (e.g. a
double-width CJK char or emoji), `cursor` overshoots `cursor_max`.
Two sites then performed unchecked `cursor_max - cursor` subtraction:

- `printer.rs:822`: initializing `max_width` for the next text chunk
- `printer.rs:934`: filling the end-of-line background

Both underflow to `~usize::MAX`, and `" ".repeat(~usize::MAX)` aborts
with "capacity overflow".

Fix: use `saturating_sub` at both sites so an overshot cursor simply
yields a fill width of 0, matching the clamping already applied
elsewhere in the same function.

Fixes sharkdp#3844
Copilot AI review requested due to automatic review settings August 1, 2026 18:47

Copilot AI left a comment

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.

Pull request overview

Fixes bat panics at extremely small terminal widths by preventing usize underflow/overflow when calculating remaining line width for wrapping and background filling.

Changes:

  • Use saturating_sub in InteractivePrinter::print_line to avoid underflow when the cursor overshoots cursor_max (e.g., wide chars at --terminal-width 1).
  • Harden Controller::print_file_ranges buffering by using saturating_add(1) and VecDeque::try_reserve to avoid capacity overflow aborts for huge --line-range offsets and return a user-facing error instead.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/printer.rs Prevents width calculations from underflowing when wrapping/background-fill occurs after cursor overshoot.
src/controller.rs Avoids VecDeque capacity overflow aborts when buffering lines for extreme --line-range offsets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/controller.rs
Comment on lines +269 to +271
buffered_lines.try_reserve(buffer_size).map_err(|_| {
format!("--line-range offset from end ({offset}) is too large to buffer")
})?;
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.

bat panics (capacity overflow) on --terminal-width 1 wrapping a double-width char with a background

2 participants