Input taller than 65535 rows loses content silently #9

Open
opened 2026-09-19 16:33:42 +09:00 by natsukium · 0 comments
Owner

Summary

main::grid_rows clamps the grid height to u16::MAX, so an input with more than ~65 535 rows
silently loses its oldest content instead of saying so.

Detail

fn grid_rows(input: &[u8], cols: u16) -> u16 {
    let lines = input.split(|&b| b == b'\n').count();
    let wrap_slack = input.len() / cols as usize;
    u16::try_from((lines + wrap_slack + 2).min(usize::from(u16::MAX))).unwrap_or(u16::MAX)
}

The doc comment states the intent: "Size the grid tall enough to hold all of stdin (plus slack for
wrapped lines) so no content scrolls out of reach before matching." Past 65 535 rows that
guarantee quietly stops holding — source::screen reads rows 0..rows of the screen, so
everything that scrolled off the top is simply not scanned, and the user is told nothing. A
tmux capture-pane -S - on a long-lived pane, or a cat of a big log, reaches this.

Also note wrap_slack = input.len() / cols counts bytes, so a UTF-8-heavy input over-estimates
the slack and reaches the ceiling sooner than its display rows warrant.

Options

  • Report it: a spoor: input truncated to the last N rows on stderr beats silence, and matches
    the project's habit of naming what was lost (the soft-wrap --help note).
  • Or keep only the tail deliberately and document it as the policy.

Either way the current behaviour — a guarantee in a doc comment that the code drops without a
word — should not stand. Related: #5, which is about reaching content that is held.

## Summary `main::grid_rows` clamps the grid height to `u16::MAX`, so an input with more than ~65 535 rows silently loses its oldest content instead of saying so. ## Detail ```rust fn grid_rows(input: &[u8], cols: u16) -> u16 { let lines = input.split(|&b| b == b'\n').count(); let wrap_slack = input.len() / cols as usize; u16::try_from((lines + wrap_slack + 2).min(usize::from(u16::MAX))).unwrap_or(u16::MAX) } ``` The doc comment states the intent: "Size the grid tall enough to hold all of stdin (plus slack for wrapped lines) so no content scrolls out of reach before matching." Past 65 535 rows that guarantee quietly stops holding — `source::screen` reads rows `0..rows` of the screen, so everything that scrolled off the top is simply not scanned, and the user is told nothing. A `tmux capture-pane -S -` on a long-lived pane, or a `cat` of a big log, reaches this. Also note `wrap_slack = input.len() / cols` counts *bytes*, so a UTF-8-heavy input over-estimates the slack and reaches the ceiling sooner than its display rows warrant. ## Options - Report it: a `spoor: input truncated to the last N rows` on stderr beats silence, and matches the project's habit of naming what was lost (the soft-wrap `--help` note). - Or keep only the tail deliberately and document it as the policy. Either way the current behaviour — a guarantee in a doc comment that the code drops without a word — should not stand. Related: #5, which is about reaching content that *is* held.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
natsukium/spoor#9
No description provided.