Commit 0fffca4
Pass a top-level JS null TurboModule arg to ObjC as nil, not NSNull (#58190)
Summary:
Changelog: [iOS][Fixed] - Pass a top-level JS `null` TurboModule argument to Objective-C as `nil` instead of `NSNull` when `enableModuleArgumentNSNullConversionIOS` is enabled
When `enableModuleArgumentNSNullConversionIOS` is on, `convertJSIValueToObjCObject`
maps a JS `null` to `(id)kCFNull`. That is the intended behaviour for nulls *nested*
inside arrays and dictionaries, but a `null` in **argument position** must still reach
Objective-C as `nil` — `NSNull` is truthy and does not respond to the selectors the
receiver expects, so leaking it crashes the callee.
The guard that enforced this lived three branches deep in
`ObjCTurboModule::setInvocationArg`, reachable only when all of the following held:
- `objCArgType == encode(id)`, and
- `getArgumentTypeName(...)` returned non-nil, and
- `RCTConvert` responded to a selector named after that type.
`getArgumentTypeName` resolves the argument type by scanning for `__rct_export__`-prefixed
selectors, which the compiler only emits for methods declared with `RCT_EXPORT_METHOD`.
Any TurboModule method without that macro — or with an `id`-typed argument, since
`[RCTConvert respondsToSelector:selector(id:)]` is `NO` — silently skipped the guard and
received `NSNull`.
This diff hoists the check to immediately after the conversion, so it applies to every
argument regardless of the method's `__rct_export__` metadata, its ObjC type encoding, or
whether an `RCTConvert` converter exists. Returning without calling `setArgument:` leaves
the `NSInvocation` slot zeroed, i.e. `nil` — identical to what the old guard did.
Behaviour is unchanged when the flag is off: the check short-circuits on the flag. Nested
`NSNull` inside arrays and dictionaries is untouched, as asserted by the new
`testInvokeTurboModuleKeepsNestedNullAsNSNullWhenFlagEnabled` case. (The flag-enabled
branch of the pre-existing `testInvokeTurboModuleWithNull` case never executes while the
flag defaults to `false`, so it did not cover this.)
The pre-existing check inside the `RCTConvert` branch is left in place. It is now
effectively unreachable — `objCArg == kCFNull` is the only way `convertedObjCArg` can be
`kCFNull`, because every `RCTConvert` converter either returns a non-`kCFNull` input
unchanged or builds a new object — but it costs nothing and keeps the diff narrow.
Differential Revision: D1179605771 parent c6b137c commit 0fffca4
2 files changed
Lines changed: 101 additions & 0 deletions
File tree
- packages/react-native/ReactCommon/react/nativemodule/core
- iostests
- platform/ios/ReactCommon
Lines changed: 94 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
| 17 | + | |
16 | 18 | | |
17 | 19 | | |
18 | 20 | | |
| |||
22 | 24 | | |
23 | 25 | | |
24 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
25 | 33 | | |
26 | 34 | | |
27 | 35 | | |
| |||
30 | 38 | | |
31 | 39 | | |
32 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
33 | 49 | | |
34 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
35 | 59 | | |
36 | 60 | | |
37 | 61 | | |
| |||
122 | 146 | | |
123 | 147 | | |
124 | 148 | | |
| 149 | + | |
| 150 | + | |
125 | 151 | | |
126 | 152 | | |
127 | 153 | | |
| |||
159 | 185 | | |
160 | 186 | | |
161 | 187 | | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
162 | 256 | | |
163 | 257 | | |
164 | 258 | | |
| |||
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
727 | 727 | | |
728 | 728 | | |
729 | 729 | | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
730 | 737 | | |
731 | 738 | | |
732 | 739 | | |
| |||
0 commit comments