callstack / callstack/react-native-bottom-tabs

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

Đang mở Phù hợp với người mới
#560 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
TypeScript
Star
1.5k
Fork
109
Merge trung bình
11 giờ 44 phút
Pull request đã merge (30 ngày)
8

Mô tả

### 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Bắt đầu tại packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm, ở các vị trí gọi onPageSelectedWithKey: và onLongPressWithKey:. Tái hiện bằng sample React Native được cung cấp với tab không phải ASCII 메시지, sau đó xác minh rằng việc nhấn và nhấn giữ tab đó không còn gây abort dưới Fabric, đồng thời key được phát ra vẫn là UTF-8 hợp lệ.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
ios, objective-c, react-native
Lĩnh vực
mobile
Loại issue
Lỗi
Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
75/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.