Repository navigation
[pigeon] Fix NSnumber edge cases and null value bug - #12997
Conversation
There was a problem hiding this comment.
Code Review
This pull request bumps the Pigeon version to 29.0.4 and introduces fixes for Swift FFI number wrapping and dictionary serialization. Specifically, it corrects dictionary serialization to check isNullish on the value rather than the key, and updates wrapNumber to check CFBooleanGetTypeID and CFNumberIsFloatType before numeric casts. Feedback suggests safely casting number to NSNumber before calling CFGetTypeID to avoid potential runtime crashes with Swift value types, and updating the corresponding test expectations.
| indent.format(''' | ||
| if CFGetTypeID(number as CFTypeRef) == CFBooleanGetTypeID(), let value = number as? Bool { | ||
| return ${_classNamePrefix}NumberWrapper(number: NSNumber(value: value), type: 3) | ||
| } | ||
| if let nsNumber = number as? NSNumber, CFNumberIsFloatType(nsNumber) { | ||
| return ${_classNamePrefix}NumberWrapper(number: nsNumber, type: 2) | ||
| } | ||
| '''); |
There was a problem hiding this comment.
Directly casting number as CFTypeRef can lead to runtime crashes if number is a Swift value type (like a custom struct or enum) that cannot be bridged to an Objective-C class, as it gets boxed in _SwiftValue which does not support CoreFoundation runtime type queries. Safely casting number to NSNumber first ensures that CFGetTypeID is only called on valid CoreFoundation objects.
indent.format('''
if let nsNumber = number as? NSNumber {
if CFGetTypeID(nsNumber as CFTypeRef) == CFBooleanGetTypeID(), let value = number as? Bool {
return ${_classNamePrefix}NumberWrapper(number: NSNumber(value: value), type: 3)
}
if CFNumberIsFloatType(nsNumber) {
return ${_classNamePrefix}NumberWrapper(number: nsNumber, type: 2)
}
}
''');| expect( | ||
| code, | ||
| contains( | ||
| 'if CFGetTypeID(number as CFTypeRef) == CFBooleanGetTypeID(), let value = number as? Bool {\n' | ||
| ' return NumberWrapper(number: NSNumber(value: value), type: 3)\n' | ||
| ' }\n' | ||
| ' if let nsNumber = number as? NSNumber, CFNumberIsFloatType(nsNumber) {\n' | ||
| ' return NumberWrapper(number: nsNumber, type: 2)\n' | ||
| ' }', | ||
| ), | ||
| ); |
There was a problem hiding this comment.
Update the test expectation to match the safer wrapNumber implementation that checks if number is an NSNumber before calling CFGetTypeID.
| expect( | |
| code, | |
| contains( | |
| 'if CFGetTypeID(number as CFTypeRef) == CFBooleanGetTypeID(), let value = number as? Bool {\n' | |
| ' return NumberWrapper(number: NSNumber(value: value), type: 3)\n' | |
| ' }\n' | |
| ' if let nsNumber = number as? NSNumber, CFNumberIsFloatType(nsNumber) {\n' | |
| ' return NumberWrapper(number: nsNumber, type: 2)\n' | |
| ' }', | |
| ), | |
| ); | |
| expect( | |
| code, | |
| contains( | |
| ' if let nsNumber = number as? NSNumber {\n' | |
| ' if CFGetTypeID(nsNumber as CFTypeRef) == CFBooleanGetTypeID(), let value = number as? Bool {\n' | |
| ' return NumberWrapper(number: NSNumber(value: value), type: 3)\n' | |
| ' }\n' | |
| ' if CFNumberIsFloatType(nsNumber) {\n' | |
| ' return NumberWrapper(number: nsNumber, type: 2)\n' | |
| ' }\n' | |
| ' }', | |
| ), | |
| ); |
stuartmorgan-g
left a comment
There was a problem hiding this comment.
LGTM with one question, but I would really recommend an integration test for this.
| } | ||
| if CFNumberIsFloatType(nsNumber) { | ||
| return NativeInteropExampleNumberWrapper(number: nsNumber, type: 2) | ||
| } |
There was a problem hiding this comment.
Why don't we need int-as-NSNumber handling here too?
There was a problem hiding this comment.
The as int check works for that
There was a problem hiding this comment.
If the as checks work, then why do we need this code at all vs. just changing the evaluation order of the existing checks?
There was a problem hiding this comment.
The issue is that ordering the switch block to handle all cases isn't possible. The bool and float checks make it so all other cases that succeed into as int work correctly.
|
autosubmit label was removed for flutter/packages/12997, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label. |
…r#193351) flutter/packages@431ea69...e55e7ac 2026-09-25 [email protected] [material_ui] Add labelTextDirection handling in InputDecorator (flutter/packages#12607) 2026-09-24 [email protected] [pigeon] Fix NSnumber edge cases and null value bug (flutter/packages#12997) 2026-09-24 [email protected] [camera] add custom path ouput to recording (flutter/packages#11774) 2026-09-24 [email protected] [Android 17] Update packages CI test runners to SDK 37 (flutter/packages#12376) 2026-09-24 [email protected] [pigeon][video_player] Disable `video_player` and `pigeon` flakes blocking latest flutter -> packages roll (flutter/packages#13003) 2026-09-24 [email protected] [google_maps_flutter] Add onPointOfInterestTap platform implementations (flutter/packages#12880) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Fixes flutter/flutter#193266
Fixes two Swift FFI value serialization bugs in
SwiftGenerator:CFBooleanand floating-pointNSNumberbridging inwrapNumber: When an Objective-C boolean (__NSCFBoolean/CFBoolean) or a whole-number floating-pointNSNumber(such as3.0returned fromUserDefaults.object(forKey:)orNSDictionary) is boxed insideAny, Swift's dynamicas? Intcast succeeds before reachingcase let value as Double:orcase let value as Bool:.wrapNumbernow checksCFGetTypeID(number as CFTypeRef) == CFBooleanGetTypeID()(type: 3) andCFNumberIsFloatType(nsNumber)(type: 2) prior to switching on numeric types, matchingFlutterStandardCodecbehavior.isNullishcheck inwriteValue: Fixes a typo inwriteValuewhere dictionary serialization checkedisNullish(key)instead ofisNullish(value)when serializing dictionary values.Fixes https://github.com/flutter/flutter/issues/<ISSUE_NUMBER>
Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2