callstack / callstack/react-native-bottom-tabs

[iOS] Fabric: SIGABRT on tab press when tab key contains non-ASCII characters (kCFStringEncodingUTF8 passed to -cStringUsingEncoding:)

Ouverte Adaptée aux débutants
#560 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
TypeScript
Étoiles
1.5k
Forks
109
Merge moyen
11 h 44 min
PR mergées (30 j)
8

Description

### Before submitting a new issue

- [x] I tested using the latest version of the library, as the bug might be already fixed.
- [x] I tested using a supported version of react native.
- [x] I checked for possible duplicate issues, with possible answers.

### Bug summary

On the New Architecture (Fabric), pressing (or long-pressing) a tab whose `key` contains any non-ASCII character — Korean, Japanese, Chinese, Cyrillic, emoji, accented Latin, … — crashes the app instantly with SIGABRT.

`RCTTabViewComponentView.mm` builds the event payloads like this ([L241](https://github.com/callstack/react-native-bottom-tabs/blob/1bbcaa2ea50b61f5daa6ccb8fe9669188c982864/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm#L241), [L250](https://github.com/callstack/react-native-bottom-tabs/blob/1bbcaa2ea50b61f5daa6ccb8fe9669188c982864/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm#L250)):

```objc
eventEmitter->onPageSelected(RNCTabViewEventEmitter::OnPageSelected{
.key = [key cStringUsingEncoding:kCFStringEncodingUTF8]
});
```

The problem: `-cStringUsingEncoding:` expects an **`NSStringEncoding`** (`NSUTF8StringEncoding` = `4`), but the code passes **`kCFStringEncodingUTF8`**, which is a **`CFStringEncoding`** constant with the value `0x08000100`. That value is not a valid `NSStringEncoding` (converting between the two families requires `CFStringConvertEncodingToNSStringEncoding()`).

What happens at runtime:

- For pure-ASCII keys the call happens to return a valid pointer (internal 8-bit buffer fast path), so the bug goes unnoticed in English-only apps.
- For keys containing non-ASCII characters, the conversion fails and `cStringUsingEncoding:` returns `NULL` (its documented behavior when the receiver cannot be converted to the given encoding). The generated `OnPageSelected` / `OnTabLongPress` structs declare `key` as `std::string`, and constructing a `std::string` from `NULL` is undefined behavior → `abort()`.

This affects every app using `@bottom-tabs/react-navigation` with non-ASCII screen names: react-navigation derives the route key from the screen name (a screen named `메시지` gets a route key like `메시지-AbC12xyz`), and that route key is exactly what is passed to `onPageSelectedWithKey:` / `onLongPressWithKey:`. Tapping such a tab crashes immediately. Standalone `TabView` usage with non-ASCII `navigationState` route keys crashes the same way.

The old architecture is not affected (the whole file is `#ifdef RCT_NEW_ARCH_ENABLED`).

### Library version

1.4.0 (latest release; the code is unchanged on current `main` — see permalinks above)

### Environment info

```shell
System:
OS: macOS 26.6.1
Binaries:
Node: 22.22.1
npmPackages:
react: 19.1.0
react-native: 0.81.5
expo: ~54.0.0
react-native-bottom-tabs: 1.4.0
@bottom-tabs/react-navigation: 1.4.0
@react-navigation/native: 7.3.14
Settings:
newArchEnabled: true (Fabric)
Tested on: iPhone Simulator (iOS 26)
```

### Steps to reproduce

1. Create a React Native 0.81 app with the New Architecture enabled and install `react-native-bottom-tabs` + `@bottom-tabs/react-navigation`.
2. Add a tab screen whose `name` contains non-ASCII characters, e.g. `메시지` (Korean).
3. Run the app on iOS and tap that tab (long-press also triggers it via `onTabLongPress`).
4. The app aborts immediately — SIGABRT from the `std::string` constructor being fed `NULL` in `RCTTabViewComponentView.mm`.

### Reproducible sample code

```js
import { NavigationContainer } from '@react-navigation/native';
import { createNativeBottomTabNavigator } from '@bottom-tabs/react-navigation';
import { Text, View } from 'react-native';

const Tab = createNativeBottomTabNavigator();

const Screen = () => (

Hello

);

export default function App() {
return (



{/* Tapping this tab crashes the app on iOS (Fabric): */}



);
}
```

### Proposed fix

Use `-UTF8String`, which returns a proper UTF-8 C string for any `NSString` contents (with a `?: ""` guard for the nil-receiver edge case), at both call sites:

```diff
--- a/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm
+++ b/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm
@@ -238,7 +238,7 @@ - (void)onPageSelectedWithKey:(NSString *)key reactTag:(NSNumber *)reactTag {
auto eventEmitter = std::static_pointer_cast(_eventEmitter);
if (eventEmitter) {
eventEmitter->onPageSelected(RNCTabViewEventEmitter::OnPageSelected{
- .key = [key cStringUsingEncoding:kCFStringEncodingUTF8]
+ .key = std::string([key UTF8String] ?: "")
});
}
}
@@ -247,7 +247,7 @@ - (void)onLongPressWithKey:(NSString *)key reactTag:(NSNumber *)reactTag {
auto eventEmitter = std::static_pointer_cast(_eventEmitter);
if (eventEmitter) {
eventEmitter->onTabLongPress(RNCTabViewEventEmitter::OnTabLongPress {
- .key = [key cStringUsingEncoding:kCFStringEncodingUTF8]
+ .key = std::string([key UTF8String] ?: "")
});
}
}
```

We are running exactly this as a `patch-package` patch in production and it fully resolves the crash. Happy to open a PR if you'd like.

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Commencez dans packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm, aux sites d’appel de onPageSelectedWithKey: et onLongPressWithKey:. Reproduisez le problème avec l’exemple React Native fourni en utilisant l’onglet non ASCII 메시지, puis vérifiez que le fait d’appuyer dessus et d’effectuer un appui long ne provoque plus d’abandon sous Fabric et que la clé émise reste un UTF-8 valide.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
ios, objective-c, react-native
Domaine
mobile
Type d'issue
Bug
Difficulté
2/5
Temps estimé
1-3 heures
Activité
Calme
Clarté
Clairement spécifiée
Accessibilité débutants
75/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.