Skip to content

Fix tag_no_case panic on case-folding byte-length changes#1885

Open
Booyaka101 wants to merge 1 commit into
rust-bakery:mainfrom
Booyaka101:fix-tag-no-case-char-boundary
Open

Fix tag_no_case panic on case-folding byte-length changes#1885
Booyaka101 wants to merge 1 commit into
rust-bakery:mainfrom
Booyaka101:fix-tag-no-case-char-boundary

Conversation

@Booyaka101

@Booyaka101 Booyaka101 commented Jun 7, 2026

Copy link
Copy Markdown

tag_no_case on &str panics with "byte index N is not a char boundary" when the matched input prefix has a different byte length than the tag — e.g. U+212A KELVIN SIGN (3 bytes) folds to ASCII 'k' (1 byte). compare_no_case correctly matches the two, but TagNoCase then split the input at tag.input_len() (the tag's byte length) instead of the matched prefix's, slicing inside the multi-byte character.

This resolves the split point with Input::slice_index over the input's own elements, so the cut always lands on a boundary. &[u8] and ASCII &str are unaffected (element count equals byte length there). Both complete and streaming go through the shared TagNoCase, so both are fixed.

Reachable from any parser using tag_no_case on attacker-controlled &str — a single character can crash the parser — so it carries a small DoS angle.

Reproducing test added to tests/issues.rs.

Fixes #1883, fixes #1884. The diagnosis is @zhangjiashuo-cs's from the issues; happy to step aside if they'd rather submit it.

tag_no_case split the input at the tag's byte length, but the matched
prefix can be a different length when case folding changes a character's
UTF-8 length (e.g. U+212A KELVIN SIGN folds to ASCII 'k'), slicing inside
a multi-byte char and panicking. Resolve the split point with
Input::slice_index over the input's own elements instead.

Fixes rust-bakery#1883
@Booyaka101 Booyaka101 requested a review from Geal as a code owner June 7, 2026 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant