Skip to content

Fix FatalExecutionEngineError on insert at start of soft-wrapped line in TextBox (#11481)#11641

Open
wnvko-msft wants to merge 2 commits into
dotnet:mainfrom
wnvko-msft:mvenkov/fix-11481-textboxview-softwrap
Open

Fix FatalExecutionEngineError on insert at start of soft-wrapped line in TextBox (#11481)#11641
wnvko-msft wants to merge 2 commits into
dotnet:mainfrom
wnvko-msft:mvenkov/fix-11481-textboxview-softwrap

Conversation

@wnvko-msft
Copy link
Copy Markdown

@wnvko-msft wnvko-msft commented May 14, 2026

Fixes #11481

Description

A TextBox with TextWrapping="Wrap" whose content includes a single long token that soft-wraps across multiple visual lines could crash the host process with a FatalExecutionEngineError when the user typed a character at the start of a soft-wrap continuation line.

TextBoxView.IncrementalMeasureLinesAfterInsert only remeasured starting at the directly inserted line, which left the preceding soft-wrap LineRecord entries pointing at stale character offsets. A subsequent measure pass read those stale records and corrupted internal state, producing the engine error.

The fix walks back over preceding soft-wrap predecessors (lines whose Length == ContentLength, i.e. lines that wrapped because text ran out of width rather than because of a hard break) before remeasuring, so the entire wrapped paragraph is re-formatted as a unit. The per-line work is extracted into a new FormatIncrementalLine helper that updates the line record and invalidates the cached visual when the line's offset or length changed.

Customer Impact

Without this fix, any WPF application that hosts a wrapping TextBox containing long unbreakable tokens (URLs, identifiers, generated strings, certain non-Latin scripts, etc.) is exposed to a hard process crash during normal text entry. FatalExecutionEngineError cannot be caught by user code, so the application terminates immediately with no opportunity for the user to save work.

Regression

No. The defective logic in IncrementalMeasureLinesAfterInsert has been present in TextBoxView since the original incremental-measure implementation; this is not introduced by a recent release.

Testing

  • Manual repro from issue Crash in TextBoxView.cs related to wrapping. #11481 confirmed to crash before the change and to insert/wrap correctly after the change: a TextBox with TextWrapping="Wrap", Width="60", FontFamily="Segoe UI", FontSize="12", and Text=" oooooooooooooooooooooooo" — place the caret at the start of the second visual line and press space.
  • Exercised additional offsets across the wrapped run (start, middle, end of each soft-wrap line) - no crashes; line metrics remain consistent with the displayed text.
  • Full PresentationFramework build under Debug|x64 passes; existing PresentationFramework.Tests suite passes.
  • An automated regression test was not added: the only available test host for this code (PresentationFramework.Tests, xunit.stafact / [WpfFact]) provides an STA thread but does not pump a Dispatcher, and the bug requires a fully realized TextBoxView (template applied, hosted in a window, layout driven by the dispatcher) to reproduce. Attempts to drive the scenario in that host either degenerated into no-op smoke tests or hung the test runner.

Risk

Low.

  • Scope is confined to one method (IncrementalMeasureLinesAfterInsert) plus a small, extracted helper (FormatIncrementalLine) in TextBoxView. No public API changes, no behavior changes for the non-soft-wrap path.
  • In the common case (insertion on a line that is not a soft-wrap continuation), the walk-back loop exits immediately on the first iteration, so the post-fix code path is equivalent to the previous code path.
  • When walk-back does occur, it is bounded by the existing _lineMetrics list and terminates as soon as a non-soft-wrap predecessor is found (or the first line is reached). It cannot run beyond the current paragraph.
  • The new helper preserves the existing line-format / line-record-update sequence and only adds an explicit visual invalidation when the line's offset or length actually changed, which mirrors the implicit invalidation behavior the old inline code relied on.
Microsoft Reviewers: Open in CodeFlow

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a hard process crash (FatalExecutionEngineError) in TextBoxView when inserting text at the start of a soft-wrapped continuation line in a wrapping TextBox. The fix updates incremental line measurement to re-format the entire affected wrapped paragraph (by walking back through soft-wrap predecessors), keeping _lineMetrics consistent and preventing stale offsets from corrupting subsequent layout.

Changes:

  • Extend IncrementalMeasureLinesAfterInsert to walk back over soft-wrap predecessor lines and re-format the wrapped paragraph as a unit.
  • Extract per-line reformatting and _lineMetrics update logic into a new FormatIncrementalLine helper and reuse it in the delete path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@wnvko-msft
Copy link
Copy Markdown
Author

@dotnet-policy-service agree company="Microsoft"

@wnvko-msft wnvko-msft added the PR metadata: Label to tag PRs, to facilitate with triage label May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Included in test pass PR Proposed PR metadata: Label to tag PRs, to facilitate with triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash in TextBoxView.cs related to wrapping.

2 participants