rustdoc: fix ICE when a grapheme cluster joins a Prepend-class character to _ or : - #160232
Merged
rust-bors[bot] merged 1 commit intoJul 31, 2026
Merged
Conversation
Collaborator
|
Thanks for the pull request, and welcome! The Rust Project is excited to review your changes, and you should hear from @notriddle (or someone else) some time within the next two weeks. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
Why was this reviewer chosen?The reviewer was selected based on:
|
… `_` `EscapeBodyTextWithWbr` iterates `text.grapheme_indices(true)`, so `i` is the start of a grapheme cluster, but the `_`/`:` word-break arm sliced at `i + 1` -- assuming a cluster containing `_` or `:` is exactly one byte long. UAX#29 GB9b joins a `Prepend`-class character (U+0600-U+0605, U+0D4E, U+111C2, ...) with the character that follows it, so a cluster can start with a multi-byte character and still contain `_`. `i + 1` then lands inside that character and `str` indexing panics. U+0D4E is `XID_Continue`, so this is reachable from an item name rustc accepts, e.g. `pub struct abc<U+0D4E>_defgh;`, and rustdoc ICEs instead of documenting the crate. Break after the whole cluster (`i + s.len()`) instead. The adjacent CamelCase arm already slices at `i`, which is always a cluster boundary, so it is unaffected. This also stops the `<wbr>` from being inserted between `_` and a combining mark that trails it, which split a grapheme cluster without panicking.
lazureykis
force-pushed
the
fix/rustdoc-escape-char-boundary
branch
from
July 30, 2026 19:23
75c7214 to
54941be
Compare
lazureykis
marked this pull request as ready for review
July 30, 2026 19:34
Contributor
|
@bors r+ |
Contributor
rust-bors Bot
pushed a commit
that referenced
this pull request
Jul 31, 2026
…uwer Rollup of 25 pull requests Successful merges: - #160204 (Sync from portable simd 2026 07 30) - #138230 (Add `raw_borrows_via_references` lint) - #158057 (Don't escape U+FF9E and U+FF9F in `escape_debug_ext`) - #160015 (refactor(mir-transform): Merge `can_be_overridden`, `is_required` and `is_enabled` into one) - #160031 (std: make positioned I/O unsupported on VxWorks) - #160125 (Fix typing mode handling in transmute checks and rustc_dump_layout) - #160152 (Create on-demand CI job for testing EC2 instances) - #160232 (rustdoc: fix ICE when a grapheme cluster joins a Prepend-class character to `_` or `:`) - #159214 (std: improve the documentation of the random feature) - #159818 (Resolve vars before calling `unnormalized_obligations`) - #159955 (Stop using higher-order macros to declare arenas) - #159958 (Fix avoid cycle for self referential return type notation) - #160040 (Split function parsing out of `item.rs` to a new module.) - #160044 (Add regression tests for fixed dead-code issues) - #160144 (renovate: group lockfiles PRs) - #160149 (Fix Windows on Arm PAC default) - #160164 (Derive `GenericTypeVisitable` for `RegionConstraint`) - #160175 (Try to recover less from incorrectly parsed const arg) - #160177 (A few more "predicate"-to-"clause" renamings) - #160181 (Mark `Tuple` and `FnPtr` traits `#[fundamental]`) - #160192 (Fix ICE for parsing issue with a closing brace) - #160209 (bootstrap: Remove method `Subcommand::kind`) - #160221 (Remove `Copy` supertrait from `VaList`) - #160223 (interpret: rename validate_operand → validate_place) - #160234 (Always use short ty path for call with missing arguments suggestion)
rust-bors Bot
pushed a commit
that referenced
this pull request
Jul 31, 2026
…uwer Rollup of 25 pull requests Successful merges: - #160204 (Sync from portable simd 2026 07 30) - #138230 (Add `raw_borrows_via_references` lint) - #158057 (Don't escape U+FF9E and U+FF9F in `escape_debug_ext`) - #160015 (refactor(mir-transform): Merge `can_be_overridden`, `is_required` and `is_enabled` into one) - #160031 (std: make positioned I/O unsupported on VxWorks) - #160125 (Fix typing mode handling in transmute checks and rustc_dump_layout) - #160152 (Create on-demand CI job for testing EC2 instances) - #160232 (rustdoc: fix ICE when a grapheme cluster joins a Prepend-class character to `_` or `:`) - #159214 (std: improve the documentation of the random feature) - #159818 (Resolve vars before calling `unnormalized_obligations`) - #159955 (Stop using higher-order macros to declare arenas) - #159958 (Fix avoid cycle for self referential return type notation) - #160040 (Split function parsing out of `item.rs` to a new module.) - #160044 (Add regression tests for fixed dead-code issues) - #160144 (renovate: group lockfiles PRs) - #160149 (Fix Windows on Arm PAC default) - #160164 (Derive `GenericTypeVisitable` for `RegionConstraint`) - #160175 (Try to recover less from incorrectly parsed const arg) - #160177 (A few more "predicate"-to-"clause" renamings) - #160181 (Mark `Tuple` and `FnPtr` traits `#[fundamental]`) - #160192 (Fix ICE for parsing issue with a closing brace) - #160209 (bootstrap: Remove method `Subcommand::kind`) - #160221 (Remove `Copy` supertrait from `VaList`) - #160223 (interpret: rename validate_operand → validate_place) - #160234 (Always use short ty path for call with missing arguments suggestion)
rust-timer
added a commit
that referenced
this pull request
Jul 31, 2026
Rollup merge of #160232 - lazureykis:fix/rustdoc-escape-char-boundary, r=notriddle rustdoc: fix ICE when a grapheme cluster joins a Prepend-class character to `_` or `:` Fixes #160231 `EscapeBodyTextWithWbr` iterates `text.grapheme_indices(true)`, so `i` is the start of a grapheme cluster, but the `_`/`:` word-break arm sliced at `i + 1` — hard-coding the assumption that a cluster containing `_` or `:` is exactly one byte long. UAX#29 GB9b joins a `Prepend`-class character (`U+0600`–`U+0605`, `U+0D4E`, `U+111C2`, …) with the character that follows it, so a cluster can start with a multi-byte character and still contain `_`. `i + 1` then lands inside that character and `str` indexing panics. `U+0D4E` is `XID_Continue`, so this is reachable from an ordinary item name that rustc accepts: ```rust pub struct abcൎ_defgh; ``` rustdoc ICEs on that with `end byte index 4 is not a char boundary; it is inside 'ൎ' (bytes 3..6 of string)`, which means `cargo doc` cannot document the crate at all. Break after the whole cluster (`i + s.len()`) instead. The adjacent CamelCase arm already slices at `i`, which is always a cluster boundary, so it needed no change. The `i + 1` dates to 3bf8bcf (which added the `:` arm) and was extended to `_` by ac303df, both in #126247. This also fixes a smaller, non-panicking case: when a combining mark trails the `_` (`first_◌̀second`), the old code inserted the `<wbr>` between `_` and its combining mark, splitting a grapheme cluster. Tests: unit cases in `src/librustdoc/html/escape/tests.rs` covering a `Prepend`+`_` cluster, a `Prepend`+`:` cluster, and the trailing-combining-mark case; plus an end-to-end regression test in `tests/rustdoc-html/` so the ICE itself stays fixed. The existing tests missed this because they only cover `Extend`-class clusters, which join backwards onto an ASCII base character and so keep `i + 1` on a boundary (`E("ṼẽçÑñéå")`, `E("V\u{0300}e\u{0300}…")`). `Prepend` is the one class that joins forwards. The property test `escape_body_text_with_wbr_makes_sense` can't reach it either — its alphabet is `[b'a', b'A', b'_']`. r? rustdoc
RalfJung
pushed a commit
to RalfJung/miri
that referenced
this pull request
Jul 31, 2026
…uwer Rollup of 25 pull requests Successful merges: - rust-lang/rust#160204 (Sync from portable simd 2026 07 30) - rust-lang/rust#138230 (Add `raw_borrows_via_references` lint) - rust-lang/rust#158057 (Don't escape U+FF9E and U+FF9F in `escape_debug_ext`) - rust-lang/rust#160015 (refactor(mir-transform): Merge `can_be_overridden`, `is_required` and `is_enabled` into one) - rust-lang/rust#160031 (std: make positioned I/O unsupported on VxWorks) - rust-lang/rust#160125 (Fix typing mode handling in transmute checks and rustc_dump_layout) - rust-lang/rust#160152 (Create on-demand CI job for testing EC2 instances) - rust-lang/rust#160232 (rustdoc: fix ICE when a grapheme cluster joins a Prepend-class character to `_` or `:`) - rust-lang/rust#159214 (std: improve the documentation of the random feature) - rust-lang/rust#159818 (Resolve vars before calling `unnormalized_obligations`) - rust-lang/rust#159955 (Stop using higher-order macros to declare arenas) - rust-lang/rust#159958 (Fix avoid cycle for self referential return type notation) - rust-lang/rust#160040 (Split function parsing out of `item.rs` to a new module.) - rust-lang/rust#160044 (Add regression tests for fixed dead-code issues) - rust-lang/rust#160144 (renovate: group lockfiles PRs) - rust-lang/rust#160149 (Fix Windows on Arm PAC default) - rust-lang/rust#160164 (Derive `GenericTypeVisitable` for `RegionConstraint`) - rust-lang/rust#160175 (Try to recover less from incorrectly parsed const arg) - rust-lang/rust#160177 (A few more "predicate"-to-"clause" renamings) - rust-lang/rust#160181 (Mark `Tuple` and `FnPtr` traits `#[fundamental]`) - rust-lang/rust#160192 (Fix ICE for parsing issue with a closing brace) - rust-lang/rust#160209 (bootstrap: Remove method `Subcommand::kind`) - rust-lang/rust#160221 (Remove `Copy` supertrait from `VaList`) - rust-lang/rust#160223 (interpret: rename validate_operand → validate_place) - rust-lang/rust#160234 (Always use short ty path for call with missing arguments suggestion)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #160231
EscapeBodyTextWithWbriteratestext.grapheme_indices(true), soiis the start of a grapheme cluster, but the_/:word-break arm sliced ati + 1— hard-coding the assumption that a cluster containing_or:is exactly one byte long.UAX#29 GB9b joins a
Prepend-class character (U+0600–U+0605,U+0D4E,U+111C2, …) with the character that follows it, so a cluster can start with a multi-byte character and still contain_.i + 1then lands inside that character andstrindexing panics.U+0D4EisXID_Continue, so this is reachable from an ordinary item name that rustc accepts:rustdoc ICEs on that with
end byte index 4 is not a char boundary; it is inside 'ൎ' (bytes 3..6 of string), which meanscargo doccannot document the crate at all.Break after the whole cluster (
i + s.len()) instead. The adjacent CamelCase arm already slices ati, which is always a cluster boundary, so it needed no change.The
i + 1dates to 3bf8bcf (which added the:arm) and was extended to_by ac303df, both in #126247.This also fixes a smaller, non-panicking case: when a combining mark trails the
_(first_◌̀second), the old code inserted the<wbr>between_and its combining mark, splitting a grapheme cluster.Tests: unit cases in
src/librustdoc/html/escape/tests.rscovering aPrepend+_cluster, aPrepend+:cluster, and the trailing-combining-mark case; plus an end-to-end regression test intests/rustdoc-html/so the ICE itself stays fixed.The existing tests missed this because they only cover
Extend-class clusters, which join backwards onto an ASCII base character and so keepi + 1on a boundary (E("ṼẽçÑñéå"),E("V\u{0300}e\u{0300}…")).Prependis the one class that joins forwards. The property testescape_body_text_with_wbr_makes_sensecan't reach it either — its alphabet is[b'a', b'A', b'_'].r? rustdoc