Backspace splits surrogate pairs (deletes one UTF-16 unit), leaving a lone surrogate on emoji/supplementary chars
Summary
Backspace in a text field deletes a single UTF-16 code unit, so pressing it after an emoji or any supplementary character splits the surrogate pair and leaves a lone surrogate, instead of deleting the whole character as browsers do.
Details
crates/obscura-cdp/src/domains/input.rs (BACKSPACE_JS):
- collapsed caret:
v.slice(0, s - 1) + v.slice(s) - legacy (
selectionStart == null):v.slice(0, -1)
For "a\\\u{1F600}b" (JS length 4) with the caret at position 3, v.slice(0, 2) keeps "a" + the high surrogate and v.slice(3) is "b", producing "a\uD83Db" — a lone surrogate. Chrome deletes the whole emoji, yielding "ab".
Fix
Before deleting at a collapsed caret (or the trailing character on the legacy path), check whether the two code units ending at that position form a surrogate pair (charCodeAt(p-1) in 0xDC00–0xDFFF and charCodeAt(p-2) in 0xD800–0xDBFF); if so, remove 2 code units. The range-delete path (non-empty selection) is already correct.
Affected
crates/obscura-cdp/src/domains/input.rs—BACKSPACE_JS
Source: h4ckf0r0day/obscura