Skip to content

feat: Introduce FlutterStringUtils for sanitizing UTF-8 data and JSON escape sequences.#179978

Closed
mahmuttaskiran wants to merge 2 commits into
flutter:masterfrom
mahmuttaskiran:flutter-sanitizer
Closed

feat: Introduce FlutterStringUtils for sanitizing UTF-8 data and JSON escape sequences.#179978
mahmuttaskiran wants to merge 2 commits into
flutter:masterfrom
mahmuttaskiran:flutter-sanitizer

Conversation

@mahmuttaskiran

@mahmuttaskiran mahmuttaskiran commented Dec 17, 2025

Copy link
Copy Markdown
Contributor

This change addresses #179727 by introducing FlutterStringUtils. With this approach, iOS and Android now behave consistently.

Please also refer to #179775 for the previous discussion and related context.

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
  • All existing and new tests are passing.

talabat.com Talabat Flutter PRs

@mahmuttaskiran mahmuttaskiran requested a review from a team as a code owner December 17, 2025 07:32
@github-actions github-actions Bot added platform-ios iOS applications specifically engine flutter/engine related. See also e: labels. a: desktop Running on desktop team-ios Owned by iOS platform team labels Dec 17, 2025

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new Objective-C++ utility, FlutterStringUtils, containing the function FlutterSanitizeUTF8ForJSON. This function is designed to sanitize NSData by performing a lossy UTF-8 decoding and replacing unpaired surrogate escape sequences. The FlutterJSONMessageCodec is modified to use this sanitization function on incoming NSData before attempting JSON deserialization, aiming to prevent crashes on invalid input. The changes include the implementation and header for FlutterStringUtils, along with corresponding unit tests in FlutterStringUtilsTest.mm and flutter_codecs_unittest.mm. Build files (BUILD.gn, framework_common.gni) are updated to include the new files. My feedback includes a suggestion to simplify the UTF-8 decoding logic for improved maintainability.

@LongCatIsLooong LongCatIsLooong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did some experiments and it turns out NSJSONSerialization can handle unpaired surrogates, if the input data is using UTF16 encoding, unfortunately the process is still lossy (those surrogates are replace with U+FFFD, same as this implementation).

Since this is a rare and "best-effort" case so ease of maintenance > performance, I think we can first turn the NSData to utf16 string and let NSJSONSerialization deserialize the utf16 data?

@LongCatIsLooong

LongCatIsLooong commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

In other words I think we can reuse logic that already exists in NSJSONSerialization class for handling unpaired surrogates instead of implementing from scratch, so it's easier to maintain:

my example Swift playground does this and it seems to work fine:

import UIKit

var data = "hello".data(using: .utf16)!
data.append(Data([0x00, 0xDB]))
let string = NSString(data: data, encoding: NSUTF16StringEncoding)!
let rawJSON = "[\"\(string)\"]"
  
let json = try? JSONSerialization.jsonObject(with: rawJSON.data(using: .utf16)!) 

@mahmuttaskiran

Copy link
Copy Markdown
Contributor Author

In other words I think we can reuse logic that already exists in NSJSONSerialization class for handling unpaired surrogates instead of implementing from scratch, so it's easier to maintain:

my example Swift playground does this and it seems to work fine:

import UIKit

var data = "hello".data(using: .utf16)!
data.append(Data([0x00, 0xDB]))
let string = NSString(data: data, encoding: NSUTF16StringEncoding)!
let rawJSON = "[\"\(string)\"]"
  
let json = try? JSONSerialization.jsonObject(with: rawJSON.data(using: .utf16)!) 

Thanks for the suggestion! I tried implementing the UTF-16 approach, but unfortunately it didn't work

When I changed the code to:

  1. Convert the sanitized string (the output of the PASS 1 in FLTSanitizeUTF8ForJSON) to UTF-16 data
  2. Pass the UTF-16 data to NSJSONSerialization

OR in FlutterJSONMessageCodec::decode

NSString* string = [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
NSData* utf16Message = [string dataUsingEncoding:NSUTF16StringEncoding];

The app crashes because NSJSONSerialization JSONObjectWithData:options:error: returns nil for the UTF-16 encoded data, even with valid JSON content. It seems NSJSONSerialization doesn't reliably parse UTF-16 encoded JSON in this context

When trying with Swift's JSONSerialization it works, but not with NSJSONSerialization, I might be missing something.

@LongCatIsLooong

Copy link
Copy Markdown
Contributor

I looked into what did the string sanitization in the swift case, it turns out to be one of the NSString initializer: https://developer.apple.com/documentation/foundation/nsstring/init(bytes:length:encoding:). And interestingly the same test implementation in objective-c doesn't replace unpaired surrogates with U+FFFD. I'll re-implement the helper in swift.

@mahmuttaskiran

Copy link
Copy Markdown
Contributor Author

I looked into what did the string sanitization in the swift case, it turns out to be one of the NSString initializer: https://developer.apple.com/documentation/foundation/nsstring/init(bytes:length:encoding:). And interestingly the same test implementation in objective-c doesn't replace unpaired surrogates with U+FFFD. I'll re-implement the helper in swift.

Alright, then I'm going to close this PR?

@LongCatIsLooong

Copy link
Copy Markdown
Contributor

I looked into what did the string sanitization in the swift case, it turns out to be one of the NSString initializer: developer.apple.com/documentation/foundation/nsstring/init(bytes:length:encoding:). And interestingly the same test implementation in objective-c doesn't replace unpaired surrogates with U+FFFD. I'll re-implement the helper in swift.

Alright, then I'm going to close this PR?

I made #181921 but ran into issues with swift name mangling. I'm going to turn this into a draft since #181921 should fix the crash when merged.

@LongCatIsLooong LongCatIsLooong marked this pull request as draft February 26, 2026 22:27
@Piinks

Piinks commented May 4, 2026

Copy link
Copy Markdown
Contributor

Hey @mahmuttaskiran, checking in here during triage. Is this superseded by #181921?

@mahmuttaskiran

Copy link
Copy Markdown
Contributor Author

Hey @mahmuttaskiran, checking in here during triage. Is this superseded by #181921?

Hey, it's yes. Closing it now. Sorry for late

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

Labels

a: desktop Running on desktop engine flutter/engine related. See also e: labels. platform-ios iOS applications specifically team-ios Owned by iOS platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants