shaping: a debug client panics in swash on a non-flag regional-indicator pair #22

Open
opened 2026-10-04 13:17:14 +09:00 by natsukium · 1 comment
Owner

A debug build of felis-client panics as soon as it draws a regional-indicator pair that is not a real flag. swash 0.2.10 overflows a subtraction while applying a GSUB contextual lookup:

panicked at swash-0.2.10/src/shape/at.rs:1097:29:
attempt to subtract with overflow

Repro (debug build, Linux): printf '🇦🇦' or printf '🇯🇯'. A real flag such as 🇯🇵 does not panic. A release build does not panic either, because overflow checks are off; whatever swash does with the wrapped value then is unverified.

Path: felis_render_wgpu::glyphs::composite_cluster → felis_shaping::Shaper::shape_cluster → shape_run → swash::shape::Shaper::shape_with → at::apply → ApplyContext::apply_contextual → apply_nested → apply_uncached → apply_subtable (at.rs:1097). Which face was resolved for the cluster was not identified (config font: Moralerspace Neon HW, plus the system color-emoji fallback).

🇦🇦 is also a repro in #17, so this blocks verifying #17 on a debug build.

Decide: check whether a newer swash fixes it upstream, and if not, guard the call (report upstream, and keep the client from dying on a shaping panic in debug).

A debug build of `felis-client` panics as soon as it draws a regional-indicator pair that is not a real flag. swash 0.2.10 overflows a subtraction while applying a GSUB contextual lookup: ``` panicked at swash-0.2.10/src/shape/at.rs:1097:29: attempt to subtract with overflow ``` **Repro** (debug build, Linux): `printf '🇦🇦'` or `printf '🇯🇯'`. A real flag such as `🇯🇵` does not panic. A release build does not panic either, because overflow checks are off; whatever swash does with the wrapped value then is unverified. **Path:** `felis_render_wgpu::glyphs::composite_cluster` → `felis_shaping::Shaper::shape_cluster` → `shape_run` → `swash::shape::Shaper::shape_with` → `at::apply` → `ApplyContext::apply_contextual` → `apply_nested` → `apply_uncached` → `apply_subtable` (at.rs:1097). Which face was resolved for the cluster was not identified (config font: Moralerspace Neon HW, plus the system color-emoji fallback). `🇦🇦` is also a repro in #17, so this blocks verifying #17 on a debug build. **Decide:** check whether a newer swash fixes it upstream, and if not, guard the call (report upstream, and keep the client from dying on a shaping panic in debug).
Author
Owner

Status: waiting on upstream swash; no felis-side guard.

  • swash 0.2.10, the version felis uses, is still the latest release on crates.io.
  • swash main still has the panicking line: src/shape/at.rs, self.extend(seqlen - 1) in the multiple-substitution path. A GSUB rule that substitutes a glyph with an empty sequence makes seqlen 0, so the subtraction underflows. This is most likely a rule in the color-emoji fallback face.

Decision: felis does not wrap shaping in catch_unwind or otherwise work around this. The panic only affects debug builds. Revisit when a swash release fixes it, or if a release build turns out to render these pairs wrong.

Status: waiting on upstream swash; no felis-side guard. - swash 0.2.10, the version felis uses, is still the latest release on crates.io. - swash `main` still has the panicking line: `src/shape/at.rs`, `self.extend(seqlen - 1)` in the multiple-substitution path. A GSUB rule that substitutes a glyph with an empty sequence makes `seqlen` 0, so the subtraction underflows. This is most likely a rule in the color-emoji fallback face. Decision: felis does not wrap shaping in `catch_unwind` or otherwise work around this. The panic only affects debug builds. Revisit when a swash release fixes it, or if a release build turns out to render these pairs wrong.
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
felis-terminal/felis#22
No description provided.