fix(ios): guard PushKit payload serialization to prevent iOS 26 SIGABRT (NSJSONSerialization throws uncatchable NSException)#123
Open
ArditXhaferi wants to merge 1 commit into
Conversation
+didReceiveIncomingPushWithPayload: forwarded the raw payload.dictionaryPayload to the RN bridge, which serializes it with NSJSONSerialization. A JSON-unsafe value (unpaired UTF-16 surrogate, NaN/Inf, non-string key/value type) makes +dataWithJSONObject:options:error: raise an ObjC NSException that is uncatchable from a Swift AppDelegate / the bridge under the iOS 26 SDK, aborting the app. Pre-flight the serialization at the call site and forward only a proven-safe body (or a minimal fallback) so a bad payload can never abort the process. Fixes react-native-webrtc#122.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #122.
Problem
On the iOS 26 SDK,
+didReceiveIncomingPushWithPayload:forType:forwards the rawpayload.dictionaryPayloadto the bridge as an event body. The bridge serializes it with+[NSJSONSerialization dataWithJSONObject:options:error:]. If the payload contains any JSON-unsafe value (unpaired UTF-16 surrogate,NaN/Infinity, non-string key, non-JSON value type),dataWithJSONObject:raises an Objective-CNSException. That exception is uncatchable from a Swift AppDelegate and from the bridge call site under iOS 26 →objc_terminate()→abort()(SIGABRT). Pre-iOS-26 toolchains masked this; the iOS 26 SDK surfaces it as a hard crash.Same bug class Expo fixed in
expo-notifications(a different code path): expo/expo#45198.Fix
Validate/sanitize the payload at this library's own call site and forward only a body proven serializable; otherwise forward a minimal fallback dict so the call still surfaces instead of aborting the process. Wrapped in
+isValidJSONObject:+@try/@catchso it can never raise past the library.NSLog).NSJSONSerializationswizzle), so it cannot affect any other library or the host app's serialization behavior.NSJSONSerializationitself as the oracle (original → lossy-ASCII → "") because an unpaired surrogate passes+isValidJSONObject:yet still throws indataWithJSONObject:.Verification
No iOS unit-test harness exists in the repo, so verified by (a) a dev client built against the iOS 26 SDK on a physical device — VoIP pushes that previously aborted now ring normally — and (b) a standalone Foundation test of the guard against real iOS Foundation:
caller_name= lone UTF-16 surrogateNaNnumberNSDatevalue