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

Open Beginner friendly
#560 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
75/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
ios, objective-c, react-native
Domain
mobile

Research direction

Start in packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm at the onPageSelectedWithKey: and onLongPressWithKey: call sites. Reproduce with the provided React Native sample using the non-ASCII 메시지 tab, then verify that pressing and long-pressing it no longer aborts under Fabric and that the emitted key remains valid UTF-8.

Written by the indexing model from the issue text.

Description

Before submitting a new issue
  • I tested using the latest version of the library, as the bug might be already fixed.
  • I tested using a supported version of react native.
  • 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, L250):

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
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
import { NavigationContainer } from '@react-navigation/native';
import { createNativeBottomTabNavigator } from '@bottom-tabs/react-navigation';
import { Text, View } from 'react-native';

const Tab = createNativeBottomTabNavigator();

const Screen = () => (
  <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
    <Text>Hello</Text>
  </View>
);

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={Screen} />
        {/* Tapping this tab crashes the app on iOS (Fabric): */}
        <Tab.Screen name="메시지" component={Screen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
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:

--- 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<const RNCTabViewEventEmitter>(_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<const RNCTabViewEventEmitter>(_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.

Dominant language
TypeScript
Stars
1.5k
Forks
108
Avg merge
12h 42m
Merged PRs (30d)
9

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from callstack/react-native-bottom-tabs

All issues in callstack/react-native-bottom-tabs

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.