Skip to content

Avoid stack overflow when rendering text with many attributed runs#57

Closed
larsjtx wants to merge 1 commit into
gonzalezreal:mainfrom
larsjtx:fix/textbuilder-stack-overflow
Closed

Avoid stack overflow when rendering text with many attributed runs#57
larsjtx wants to merge 1 commit into
gonzalezreal:mainfrom
larsjtx:fix/textbuilder-stack-overflow

Conversation

@larsjtx

@larsjtx larsjtx commented May 11, 2026

Copy link
Copy Markdown

TextBuilder reduced the per-run Text values via Text("\(partialResult)\(text)"), wrapping every run in a LocalizedStringKey-backed Text. SwiftUI's LocalizedStringKey.resolve walks that chain at render time and recurses ~8 stack frames per nesting level, overflowing the main-thread stack for content that produces a few hundred runs (emoji-dense notes are an easy trigger — each emoji becomes its own run). Switching to Text + Text produces concat storage that resolves linearly.

No regression test included: the crash only manifests inside SwiftUI's render pass on the main thread, which swift test doesn't exercise; a "construct 500-run Text and don't crash" test would either pass trivially (no render) or take the test runner down with it (if regressed). Happy to add one if you have a pattern in mind.

Fixes #56

The reduce in TextBuilder built the result via Text("\(partialResult)\(text)"),
wrapping every attributed run in a LocalizedStringKey-backed Text.
At render time, SwiftUI's LocalizedStringKey.resolve walks the chain
and recurses ~8 stack frames per nesting level, overflowing the
main-thread stack for content that produces a few hundred runs
(e.g. emoji-dense notes where each emoji forms its own run).

Switch to Text + Text concatenation, which produces concat storage
that resolves linearly.

Fixes gonzalezreal#56
@gonzalezreal

Copy link
Copy Markdown
Owner

Sorry for the very late follow-up, and thank you for the fix!

I merged #65, which fixes the same TextBuilder stack overflow and adds a regression test, so I’m going to close this one as superseded.

I really appreciate you digging into this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash

2 participants