Skip to content

fix: prevent panic in search highlighting on multibyte text#66

Merged
gavin-jeong merged 1 commit into
masterfrom
fix/highlight-multibyte-panic
Jul 14, 2026
Merged

fix: prevent panic in search highlighting on multibyte text#66
gavin-jeong merged 1 commit into
masterfrom
fix/highlight-multibyte-panic

Conversation

@gavin-jeong

Copy link
Copy Markdown
Collaborator

Summary

  • buildSnippet sliced search snippets at fixed byte offsets (firstMatch ± 40/80) without respecting UTF-8 rune boundaries, which could split a multibyte character (e.g. Korean) in half and produce invalid UTF-8.
  • highlightMatches then called strings.ToLower on that invalid text; Go's invalid-byte → U+FFFD substitution can make the lowercased string longer than the original in byte length.
  • Highlight spans were computed against the lowercased string but then sliced directly out of the original text, so a span's end could exceed len(text), causing panic: runtime error: slice bounds out of range.

Fix

  • buildSnippet: snap start/end to the nearest rune boundary via utf8.RuneStart before slicing.
  • highlightMatches: clamp each span against len(text) (and the running cursor) before slicing, guarding against any remaining case-folding length divergence (e.g. Turkish İ, German ẞ).

Test plan

  • Added TestBuildSnippet_MultibyteBoundary — exercises snippet building around Korean text at every byte offset.
  • Added TestHighlightMatches_NoPanicOnCaseFoldLengthChange — Turkish İ case-folding length change, asserts no panic.
  • go build ./..., go vet ./..., go test ./... all pass.

buildSnippet sliced snippets at fixed byte offsets without respecting
UTF-8 rune boundaries, which could split multibyte characters (e.g.
Korean) and produce invalid UTF-8. highlightMatches then lowercased
that text for matching, and Go's invalid-byte-to-U+FFFD substitution
could make the lowercased string longer than the original, causing
highlight spans computed against it to overrun the original text and
panic on slice-bounds-out-of-range.

Snap snippet boundaries to rune starts, and clamp highlight spans
against the actual text length before slicing.

@jinsekim jinsekim left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM!

@jinsekim jinsekim added the auto-review/approved Auto-approved by the Slack auto-reviewer bot label Jul 13, 2026

@jinsekim jinsekim left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM!

@gavin-jeong
gavin-jeong merged commit e7cf385 into master Jul 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-review/approved Auto-approved by the Slack auto-reviewer bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants