Repository navigation
Fix DeleteSurrounding splitting UTF-16 surrogate pairs - #190514
auto-submit[bot] merged 8 commits into
Conversation
TextInputModel::DeleteSurrounding advanced the end of the deletion range by inspecting the character at start on every iteration instead of the one at end. When a later code point in the range was non-BMP, end landed inside a surrogate pair and the erase left a lone surrogate in text_, aborting the process on the next UTF-16 to UTF-8 conversion. Fixes flutter#190046
There was a problem hiding this comment.
Code Review
This pull request fixes a bug in TextInputModel::DeleteSurrounding where deleting across non-BMP code points could leave a lone surrogate behind, corrupting the text. The fix ensures that the character at the position being advanced past is checked rather than the starting position, and updates loop bounds checks from inequality to less-than comparisons. Additionally, several unit tests are added to verify deleting surrounding wide characters under various scenarios. There are no review comments, so I have no feedback to provide.
d31df22 to
d14198e
Compare
TextInputModel::DeleteSurrounding advanced the end of the deletion range by inspecting the character at start on every iteration instead of the one at end. When a later code point in the range was non-BMP, end landed inside a surrogate pair and the erase left a lone surrogate in text_, aborting the process on the next UTF-16 to UTF-8 conversion. Fixes flutter#190046
d14198e to
6581a11
Compare
|
Hi @LongCatIsLooong I update the branch with master and "team-macos" disappear. Could you add it again? |
Renzo-Olivares
left a comment
There was a problem hiding this comment.
@Vi-debug thank you for the contribution! Left a few small comments but overall the change looks good to me.
There was a problem hiding this comment.
Should the change in guard in the forward loop, also apply similarly for the backwards loop since we can move in steps of 2 potentially skipping the exact start of the range?
There was a problem hiding this comment.
Good catch. I fixed it. Thanks for noticing
| EXPECT_STREQ(model->GetText().c_str(), "ABCE"); | ||
| } | ||
|
|
||
| // Regression test for https://github.com/flutter/flutter/issues/190046. |
There was a problem hiding this comment.
We should also add regression tests for the guard changes. The test should fail with the old guard and pass with the new guard.
There was a problem hiding this comment.
Added two regression tests isolating just the guard changes DeleteSurroundingGuardStopsAtComposingEnd for the forward guard and DeleteSurroundingGuardStopsAtComposingStart for the backward guard fixed
DeleteSurrounding's backward loop compared start == editable_range().start() to detect reaching the start of the range, but a 2-wide step across a surrogate pair can land start before that position instead of exactly on it -- the same hazard just fixed for the forward end != max_pos guard. Use <= instead, and add regression tests isolating both guard changes. Addresses review feedback from Renzo-Olivares on flutter#190514.
…airs' into fix-delete-surrounding-surrogate-pairs # Conflicts: # engine/src/flutter/shell/platform/common/text_input_model_unittests.cc
There was a problem hiding this comment.
Code Review
This pull request updates TextInputModel::DeleteSurrounding to correctly handle surrogate pairs and boundary conditions when deleting surrounding text, preventing lone surrogates and out-of-bounds errors, and adds corresponding regression tests. Feedback points out a potential issue where start can become negative when stepping backward across surrogate pairs, leading to an out-of-bounds read, and suggests clamping start to 0.
Adding the selection()/composing_range() assertions Renzo-Olivares requested on flutter#190514 exposed two bugs in how DeleteSurrounding adjusted composing_range_: shifting only the end by deleted_length underflowed (size_t) whenever a surrogate pair pushed the deletion past the stored end, and the start was never adjusted when the deletion began before it, leaving a stale bound. Clamp both bounds against the deleted span instead of shifting only the end. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_012gKRyXkFH3AkJb1Xiqyfvo
Adding the selection()/composing_range() assertions Renzo-Olivares requested on flutter#190514 exposed two bugs in how DeleteSurrounding adjusted composing_range_: shifting only the end by deleted_length underflowed (size_t) whenever a surrogate pair pushed the deletion past the stored end, and the start was never adjusted when the deletion began before it, leaving a stale bound. Clamp both bounds against the deleted span instead of shifting only the end.
8376a33 to
059661a
Compare
LongCatIsLooong
left a comment
There was a problem hiding this comment.
Sorry forgot to press the submit review button. LGTM with a comment nit.
|
Could you also sync this to head since ci.yaml validation is failing. |
|
Also /cc @cbracken, I think the PR I mentioned in #191868 (comment) |
|
Updated PR. Waiting for @LongCatIsLooong check again |
|
@LongCatIsLooong Pls help me trigger merge for this PR |
…12760) Manual roll Flutter from 70797e15325e to 5a6cfa7f3d26 (52 revisions) Manual roll requested by [email protected] flutter/flutter@70797e1...5a6cfa7 2026-09-04 [email protected] [tool] Migrate ScreenshotCommand to modular dependency injection (flutter/flutter#190767) 2026-09-04 [email protected] Roll Skia from 8fce167bdded to 93ac1e630d1d (3 revisions) (flutter/flutter#192306) 2026-09-04 [email protected] Add iOS Universal Link integration test (Simulator) (flutter/flutter#191443) 2026-09-04 [email protected] [AGP 9.1.0 Migration #5] Delete getLegacyAndroidExtension and migrate NDK fallback to public DSL (flutter/flutter#192116) 2026-09-04 [email protected] Reland "[tool_tests] Remove bringup from Windows tool_tests_commands_2_2" (#191732) (flutter/flutter#191802) 2026-09-04 [email protected] [flutter_tools] Fix unhandled DebugAdapterException on early process termination (flutter/flutter#192294) 2026-09-04 [email protected] Roll Packages from f9b3954 to 9af9c60 (4 revisions) (flutter/flutter#192292) 2026-09-04 [email protected] Roll Skia from 2e3f7e07eee6 to 8fce167bdded (5 revisions) (flutter/flutter#192283) 2026-09-04 [email protected] Roll Fuchsia Linux SDK from GTZNkoIR_WegRPWgL... to FgDQeF6jb1dVRVh3K... (flutter/flutter#192276) 2026-09-04 [email protected] Roll Skia from b6b00df360e5 to 2e3f7e07eee6 (2 revisions) (flutter/flutter#192275) 2026-09-04 [email protected] [iOS] TextField should support typing accented words with external keyboard (flutter/flutter#191062) 2026-09-04 [email protected] Roll Skia from 1f68c0b16f17 to b6b00df360e5 (7 revisions) (flutter/flutter#192269) 2026-09-04 [email protected] [flutter_tools] add typed enum and defaulted option descriptors (flutter/flutter#191760) 2026-09-04 [email protected] Roll Dart SDK from c2edc382a4f8 to 5501d02b583d (1 revision) (flutter/flutter#192263) 2026-09-04 [email protected] [Linux] Use fences to synchronize frames between OpenGL contexts (flutter/flutter#192098) 2026-09-03 [email protected] Defer semantics geometry updates for blocked branches (flutter/flutter#192146) 2026-09-03 [email protected] Roll Skia from 8d3e197531c6 to 1f68c0b16f17 (8 revisions) (flutter/flutter#192244) 2026-09-03 [email protected] Fix DeleteSurrounding splitting UTF-16 surrogate pairs (flutter/flutter#190514) 2026-09-03 [email protected] Remove no-shuffle from progress indicator test (flutter/flutter#186655) 2026-09-03 [email protected] [material] Remove unused parameters from constructors of generic test class (flutter/flutter#191764) 2026-09-03 [email protected] Handle linear and radial gradients in UberSDF (re-implement after fix) (flutter/flutter#192124) 2026-09-03 [email protected] Roll Dart SDK from fcbfb64f42a1 to c2edc382a4f8 (2 revisions) (flutter/flutter#192240) 2026-09-03 [email protected] Fix parsing of --enable-hcpp-and-surface-control switch and add --no-enable-hcpp tests (flutter/flutter#192202) 2026-09-03 [email protected] Fix issue where shapes rendered with gradient+blur+rotation end up incorrectly cut off (flutter/flutter#192136) 2026-09-03 [email protected] Fix sibling nodes crash under MergeSemantics (flutter/flutter#191587) 2026-09-03 [email protected] Makes backdrop groups operate on the union. (flutter/flutter#191838) 2026-09-03 [email protected] Roll Skia from 008936396810 to 8d3e197531c6 (1 revision) (flutter/flutter#192236) 2026-09-03 [email protected] [docs] Remove superseded AI rules for Flutter (flutter/flutter#192185) 2026-09-03 [email protected] Collect analytics about SwiftPM errors and warnings (flutter/flutter#191746) 2026-09-03 [email protected] Roll Packages from 18fe786 to f9b3954 (7 revisions) (flutter/flutter#192235) 2026-09-03 [email protected] [Linux] Remove frame sharing between OpenGL contexts (flutter/flutter#192150) 2026-09-03 [email protected] Roll Dart SDK from cf79067a1e44 to fcbfb64f42a1 (1 revision) (flutter/flutter#192228) 2026-09-03 [email protected] Roll Skia from 731fe9af4c0b to 008936396810 (3 revisions) (flutter/flutter#192225) 2026-09-03 [email protected] Roll Dart SDK from 700ab60bfe53 to cf79067a1e44 (2 revisions) (flutter/flutter#192219) 2026-09-03 [email protected] Roll Skia from 823f82e18177 to 731fe9af4c0b (5 revisions) (flutter/flutter#192217) 2026-09-03 [email protected] Fixes OverlayPortal semantics bounds corruption (flutter/flutter#192139) 2026-09-03 [email protected] Roll Fuchsia Linux SDK from idslm9FikVLy2K_A-... to GTZNkoIR_WegRPWgL... (flutter/flutter#192215) 2026-09-03 [email protected] Roll Fuchsia Test Scripts from u_fSMsPU22VvUsvSo... to VObjlh3xw2P9sEbC_... (flutter/flutter#192212) 2026-09-03 [email protected] Roll Skia from ae22da2e8308 to 823f82e18177 (13 revisions) (flutter/flutter#192209) 2026-09-02 [email protected] Expose skipTraversal in FocusableActionDetector (flutter/flutter#191308) 2026-09-02 [email protected] Add `IsProgram` mock method to `MockGLESImpl`, use it in `BufferBindingsGLESTest` (flutter/flutter#192196) 2026-09-02 [email protected] Fix nested scroll view fling crash (flutter/flutter#191130) 2026-09-02 [email protected] Fix TabBarView/PageView edge auto-scroll during mouse text selection (flutter/flutter#189544) 2026-09-02 [email protected] Bypass gamma correction when alpha >= 1.0 (flutter/flutter#192193) ...
…lutter#12760) Manual roll Flutter from 70797e15325e to 5a6cfa7f3d26 (52 revisions) Manual roll requested by [email protected] flutter/flutter@70797e1...5a6cfa7 2026-09-04 [email protected] [tool] Migrate ScreenshotCommand to modular dependency injection (flutter/flutter#190767) 2026-09-04 [email protected] Roll Skia from 8fce167bdded to 93ac1e630d1d (3 revisions) (flutter/flutter#192306) 2026-09-04 [email protected] Add iOS Universal Link integration test (Simulator) (flutter/flutter#191443) 2026-09-04 [email protected] [AGP 9.1.0 Migration flutter#5] Delete getLegacyAndroidExtension and migrate NDK fallback to public DSL (flutter/flutter#192116) 2026-09-04 [email protected] Reland "[tool_tests] Remove bringup from Windows tool_tests_commands_2_2" (#191732) (flutter/flutter#191802) 2026-09-04 [email protected] [flutter_tools] Fix unhandled DebugAdapterException on early process termination (flutter/flutter#192294) 2026-09-04 [email protected] Roll Packages from f9b3954 to 9af9c60 (4 revisions) (flutter/flutter#192292) 2026-09-04 [email protected] Roll Skia from 2e3f7e07eee6 to 8fce167bdded (5 revisions) (flutter/flutter#192283) 2026-09-04 [email protected] Roll Fuchsia Linux SDK from GTZNkoIR_WegRPWgL... to FgDQeF6jb1dVRVh3K... (flutter/flutter#192276) 2026-09-04 [email protected] Roll Skia from b6b00df360e5 to 2e3f7e07eee6 (2 revisions) (flutter/flutter#192275) 2026-09-04 [email protected] [iOS] TextField should support typing accented words with external keyboard (flutter/flutter#191062) 2026-09-04 [email protected] Roll Skia from 1f68c0b16f17 to b6b00df360e5 (7 revisions) (flutter/flutter#192269) 2026-09-04 [email protected] [flutter_tools] add typed enum and defaulted option descriptors (flutter/flutter#191760) 2026-09-04 [email protected] Roll Dart SDK from c2edc382a4f8 to 5501d02b583d (1 revision) (flutter/flutter#192263) 2026-09-04 [email protected] [Linux] Use fences to synchronize frames between OpenGL contexts (flutter/flutter#192098) 2026-09-03 [email protected] Defer semantics geometry updates for blocked branches (flutter/flutter#192146) 2026-09-03 [email protected] Roll Skia from 8d3e197531c6 to 1f68c0b16f17 (8 revisions) (flutter/flutter#192244) 2026-09-03 [email protected] Fix DeleteSurrounding splitting UTF-16 surrogate pairs (flutter/flutter#190514) 2026-09-03 [email protected] Remove no-shuffle from progress indicator test (flutter/flutter#186655) 2026-09-03 [email protected] [material] Remove unused parameters from constructors of generic test class (flutter/flutter#191764) 2026-09-03 [email protected] Handle linear and radial gradients in UberSDF (re-implement after fix) (flutter/flutter#192124) 2026-09-03 [email protected] Roll Dart SDK from fcbfb64f42a1 to c2edc382a4f8 (2 revisions) (flutter/flutter#192240) 2026-09-03 [email protected] Fix parsing of --enable-hcpp-and-surface-control switch and add --no-enable-hcpp tests (flutter/flutter#192202) 2026-09-03 [email protected] Fix issue where shapes rendered with gradient+blur+rotation end up incorrectly cut off (flutter/flutter#192136) 2026-09-03 [email protected] Fix sibling nodes crash under MergeSemantics (flutter/flutter#191587) 2026-09-03 [email protected] Makes backdrop groups operate on the union. (flutter/flutter#191838) 2026-09-03 [email protected] Roll Skia from 008936396810 to 8d3e197531c6 (1 revision) (flutter/flutter#192236) 2026-09-03 [email protected] [docs] Remove superseded AI rules for Flutter (flutter/flutter#192185) 2026-09-03 [email protected] Collect analytics about SwiftPM errors and warnings (flutter/flutter#191746) 2026-09-03 [email protected] Roll Packages from 18fe786 to f9b3954 (7 revisions) (flutter/flutter#192235) 2026-09-03 [email protected] [Linux] Remove frame sharing between OpenGL contexts (flutter/flutter#192150) 2026-09-03 [email protected] Roll Dart SDK from cf79067a1e44 to fcbfb64f42a1 (1 revision) (flutter/flutter#192228) 2026-09-03 [email protected] Roll Skia from 731fe9af4c0b to 008936396810 (3 revisions) (flutter/flutter#192225) 2026-09-03 [email protected] Roll Dart SDK from 700ab60bfe53 to cf79067a1e44 (2 revisions) (flutter/flutter#192219) 2026-09-03 [email protected] Roll Skia from 823f82e18177 to 731fe9af4c0b (5 revisions) (flutter/flutter#192217) 2026-09-03 [email protected] Fixes OverlayPortal semantics bounds corruption (flutter/flutter#192139) 2026-09-03 [email protected] Roll Fuchsia Linux SDK from idslm9FikVLy2K_A-... to GTZNkoIR_WegRPWgL... (flutter/flutter#192215) 2026-09-03 [email protected] Roll Fuchsia Test Scripts from u_fSMsPU22VvUsvSo... to VObjlh3xw2P9sEbC_... (flutter/flutter#192212) 2026-09-03 [email protected] Roll Skia from ae22da2e8308 to 823f82e18177 (13 revisions) (flutter/flutter#192209) 2026-09-02 [email protected] Expose skipTraversal in FocusableActionDetector (flutter/flutter#191308) 2026-09-02 [email protected] Add `IsProgram` mock method to `MockGLESImpl`, use it in `BufferBindingsGLESTest` (flutter/flutter#192196) 2026-09-02 [email protected] Fix nested scroll view fling crash (flutter/flutter#191130) 2026-09-02 [email protected] Fix TabBarView/PageView edge auto-scroll during mouse text selection (flutter/flutter#189544) 2026-09-02 [email protected] Bypass gamma correction when alpha >= 1.0 (flutter/flutter#192193) ...
…lutter#12760) Manual roll Flutter from 70797e15325e to 5a6cfa7f3d26 (52 revisions) Manual roll requested by [email protected] flutter/flutter@70797e1...5a6cfa7 2026-09-04 [email protected] [tool] Migrate ScreenshotCommand to modular dependency injection (flutter/flutter#190767) 2026-09-04 [email protected] Roll Skia from 8fce167bdded to 93ac1e630d1d (3 revisions) (flutter/flutter#192306) 2026-09-04 [email protected] Add iOS Universal Link integration test (Simulator) (flutter/flutter#191443) 2026-09-04 [email protected] [AGP 9.1.0 Migration flutter#5] Delete getLegacyAndroidExtension and migrate NDK fallback to public DSL (flutter/flutter#192116) 2026-09-04 [email protected] Reland "[tool_tests] Remove bringup from Windows tool_tests_commands_2_2" (#191732) (flutter/flutter#191802) 2026-09-04 [email protected] [flutter_tools] Fix unhandled DebugAdapterException on early process termination (flutter/flutter#192294) 2026-09-04 [email protected] Roll Packages from f9b3954 to 9af9c60 (4 revisions) (flutter/flutter#192292) 2026-09-04 [email protected] Roll Skia from 2e3f7e07eee6 to 8fce167bdded (5 revisions) (flutter/flutter#192283) 2026-09-04 [email protected] Roll Fuchsia Linux SDK from GTZNkoIR_WegRPWgL... to FgDQeF6jb1dVRVh3K... (flutter/flutter#192276) 2026-09-04 [email protected] Roll Skia from b6b00df360e5 to 2e3f7e07eee6 (2 revisions) (flutter/flutter#192275) 2026-09-04 [email protected] [iOS] TextField should support typing accented words with external keyboard (flutter/flutter#191062) 2026-09-04 [email protected] Roll Skia from 1f68c0b16f17 to b6b00df360e5 (7 revisions) (flutter/flutter#192269) 2026-09-04 [email protected] [flutter_tools] add typed enum and defaulted option descriptors (flutter/flutter#191760) 2026-09-04 [email protected] Roll Dart SDK from c2edc382a4f8 to 5501d02b583d (1 revision) (flutter/flutter#192263) 2026-09-04 [email protected] [Linux] Use fences to synchronize frames between OpenGL contexts (flutter/flutter#192098) 2026-09-03 [email protected] Defer semantics geometry updates for blocked branches (flutter/flutter#192146) 2026-09-03 [email protected] Roll Skia from 8d3e197531c6 to 1f68c0b16f17 (8 revisions) (flutter/flutter#192244) 2026-09-03 [email protected] Fix DeleteSurrounding splitting UTF-16 surrogate pairs (flutter/flutter#190514) 2026-09-03 [email protected] Remove no-shuffle from progress indicator test (flutter/flutter#186655) 2026-09-03 [email protected] [material] Remove unused parameters from constructors of generic test class (flutter/flutter#191764) 2026-09-03 [email protected] Handle linear and radial gradients in UberSDF (re-implement after fix) (flutter/flutter#192124) 2026-09-03 [email protected] Roll Dart SDK from fcbfb64f42a1 to c2edc382a4f8 (2 revisions) (flutter/flutter#192240) 2026-09-03 [email protected] Fix parsing of --enable-hcpp-and-surface-control switch and add --no-enable-hcpp tests (flutter/flutter#192202) 2026-09-03 [email protected] Fix issue where shapes rendered with gradient+blur+rotation end up incorrectly cut off (flutter/flutter#192136) 2026-09-03 [email protected] Fix sibling nodes crash under MergeSemantics (flutter/flutter#191587) 2026-09-03 [email protected] Makes backdrop groups operate on the union. (flutter/flutter#191838) 2026-09-03 [email protected] Roll Skia from 008936396810 to 8d3e197531c6 (1 revision) (flutter/flutter#192236) 2026-09-03 [email protected] [docs] Remove superseded AI rules for Flutter (flutter/flutter#192185) 2026-09-03 [email protected] Collect analytics about SwiftPM errors and warnings (flutter/flutter#191746) 2026-09-03 [email protected] Roll Packages from 18fe786 to f9b3954 (7 revisions) (flutter/flutter#192235) 2026-09-03 [email protected] [Linux] Remove frame sharing between OpenGL contexts (flutter/flutter#192150) 2026-09-03 [email protected] Roll Dart SDK from cf79067a1e44 to fcbfb64f42a1 (1 revision) (flutter/flutter#192228) 2026-09-03 [email protected] Roll Skia from 731fe9af4c0b to 008936396810 (3 revisions) (flutter/flutter#192225) 2026-09-03 [email protected] Roll Dart SDK from 700ab60bfe53 to cf79067a1e44 (2 revisions) (flutter/flutter#192219) 2026-09-03 [email protected] Roll Skia from 823f82e18177 to 731fe9af4c0b (5 revisions) (flutter/flutter#192217) 2026-09-03 [email protected] Fixes OverlayPortal semantics bounds corruption (flutter/flutter#192139) 2026-09-03 [email protected] Roll Fuchsia Linux SDK from idslm9FikVLy2K_A-... to GTZNkoIR_WegRPWgL... (flutter/flutter#192215) 2026-09-03 [email protected] Roll Fuchsia Test Scripts from u_fSMsPU22VvUsvSo... to VObjlh3xw2P9sEbC_... (flutter/flutter#192212) 2026-09-03 [email protected] Roll Skia from ae22da2e8308 to 823f82e18177 (13 revisions) (flutter/flutter#192209) 2026-09-02 [email protected] Expose skipTraversal in FocusableActionDetector (flutter/flutter#191308) 2026-09-02 [email protected] Add `IsProgram` mock method to `MockGLESImpl`, use it in `BufferBindingsGLESTest` (flutter/flutter#192196) 2026-09-02 [email protected] Fix nested scroll view fling crash (flutter/flutter#191130) 2026-09-02 [email protected] Fix TabBarView/PageView edge auto-scroll during mouse text selection (flutter/flutter#189544) 2026-09-02 [email protected] Bypass gamma correction when alpha >= 1.0 (flutter/flutter#192193) ...
DeleteSurrounding(offset, count)deletescountcode points, buttext_is UTF-16, where a code point is 1 or 2 units. So the loop that walks the deletion range has to ask, at each step, "is the unit I'm about to step over a lead surrogate?" — and advance by 2 if so, 1 otherwise.The old code asked that question about the wrong position:
startnever moves inside the loop, so every iteration re-tested the same unit — the one the range began at — instead of the unitendcurrently sits on. The fix is to test the moving cursor:Concretely, for
"a😀"(units:a,D83D,DE00) deleting 2 code points from 0:That orphan is what killed the process: the next
GetText()runsfml::Utf16ToUtf8, a lone surrogate is invalid UTF-16, and with the engine built-fno-exceptionsthe resultingrange_errorbecomes an abort instead of a throw. The mirror-image case — non-BMP first, BMP after — over-advanced instead, silently deleting extra characters.The second half of the fix is the loop guard,
end != max_pos→end < max_pos. Now that steps can be 2 wide,endcan jump overmax_posrather than landing on it — a pair straddling the end of a composing range does this. With!=, the guard would then never be satisfied and the loop would keep reading past the end of the range, walkingtext_.at()off the string and aborting the same way.<stops it. The same reasoning applies to thestartloop above it, which advances by the same 1-or-2 rule.Fixes #190046
Pre-launch Checklist
///).