Skip to content

fix(HUB-0000): ignore a foreign device-lost message and clamp truncated ranges - #104

Draft
chris-addison wants to merge 1 commit into
unity/hub-consolidatedfrom
fix/HUB-0000-gh19640-device-lost-token
Draft

chris-addison wants to merge 1 commit into
unity/hub-consolidatedfrom
fix/HUB-0000-gh19640-device-lost-token

Conversation

@chris-addison

Copy link
Copy Markdown
Collaborator

Claudistopher Claudistopher:

On Windows, a gpui window now ignores a device-lost message unless it carries the app's validation number. Inline text truncation also clamps its ranges to char boundaries.

For Unity-Technologies/unity-hub#19640 (Sentry UNITY-HUB-39QA, UNITY-HUB-39QB, UNITY-HUB-39QC).

The changes I made:

  • Device-lost message from another process: before, the window procedure read the lparam of any WM_USER + 7 as a pointer to the app's DirectXDevices, without checking wparam. IMEs, overlays and accessibility tools also send that number, so the Hub read a random address: a null one crashed at 0x10 (39QA), a random one could corrupt memory. Now it returns early when wparam is not the validation number, as the cursor message (HUB-8759) and the platform window's messages already do. The real sender, the VSync thread, already passes the number.
  • Truncated inline text: InlineDocument::truncated now clamps every style and span range to char boundaries of the truncated text and drops a range left empty. A source range that ended inside a multi-byte character mapped to a split in the output, and the text system slices the output by these ranges.

Cause: the device-lost handler was the one WM_USER handler that trusted lparam without the token. The 39QB panic index decodes to the bytes of the string "Inter", so a range was read from memory that a string had reused. That points at memory corruption, which the first fix addresses; the clamp keeps a bad range from panicking.

What could go wrong: a sender of the real message that does not pass the validation number would now be ignored. The only sender in the tree passes it.

Where to start reviewing:

handle_device_lost in crates/gpui_windows/src/events.rs, then clamp_to_char_boundaries in crates/gpui/src/elements/div/inline.rs.

How To Test/Validate:

  1. Run cargo test -p gpui-ce --lib elements::div::inline::tests: four tests cover a short string, a range far past the end, and ranges that start or end inside "é" and "🦀".
  2. On a Windows machine that can create a Direct3D device, run cargo test -p gpui_ce_windows --features test-support --lib a_foreign_device_lost_message_is_ignored. It sends WM_USER + 7 without the token, with a null and a non-null lparam, and checks the window survives with its renderer unchanged.

Evidence: the four truncation tests pass. The multi-byte test fails without the clamp, because its ranges then start inside "é".

Not tested: the window test did not run. The Windows machine I used cannot create a Direct3D device in its session, so this test and the four existing renderer and window tests fail there at device creation. Also not tested: a real third-party sender or a real driver reset.

AI use:

Claude wrote the fixes, the tests and this description. The author checks the token guard against the HUB-8759 cursor fix.

🤖 Generated with Claude Code

…nd clamp truncated ranges

A window read WM_USER+7's lparam as a DirectXDevices pointer without
checking wparam for the validation number, so a message from another
process or DLL made it read a random address. InlineDocument::truncated
also clamps the ranges it maps to char boundaries of its output text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant