Skip to content

fix(ios): launch on iOS 17 and older when built with Xcode 27 - #434

Open
mfazekas wants to merge 4 commits into
mainfrom
fix/ios-xcode27-exception-ptr
Open

mfazekas wants to merge 4 commits into
mainfrom
fix/ios-xcode27-exception-ptr

Conversation

@mfazekas

@mfazekas mfazekas commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Apps built with Xcode 27 abort at launch on iOS < 18 with dyld: Symbol not found: __ZNSt13exception_ptr31__from_native_exception_pointerEPv (#433, margelo/nitro#1652). Swift's explicit module builds compile libc++ for the SDK version instead of the deployment target, so std::make_exception_ptr in Swift-compiled Nitro code (NitroModules and our generated specs) references std::exception_ptr::__from_native_exception_pointer and __cxa_init_primary_exception, which only exist in the iOS 18+ system libc++.

ios/LibcxxExceptionPtrBackport.mm defines both for deployment targets below 18, building the exception the way libc++ itself does for iOS < 18 (throw, then std::current_exception), so the references resolve inside the app. With use_frameworks! :dynamic the reference lives in NitroModules.framework, which our pod can't reach, so the README documents a Podfile setting for that case.

Verified with Xcode 27.1 on an iOS 17.5 simulator: the unfixed example crashes at launch; with the fix it launches and the new Issue #433 exception_ptr reproducer rejects ~3,000 native promises with 0 unexpected results, for static libraries and use_frameworks! :static. :dynamic plus the README setting also passes. The fixed build still runs on iOS 26.5.

The backport is temporary: once the react-native-nitro-modules peer range starts at a release with margelo/nitro#1824 (expected 0.37.2), scripts/__tests__/libcxx-backport-removal.test.ts fails and points at what to delete (the .mm, its README note and the test).

Swift-compiled Nitro code references two iOS 18-only libc++ symbols when
built with Xcode 27, so dyld aborts at launch on iOS < 18 (#433,
margelo/nitro#1652). Define fallbacks for deployment targets below 18 so
the references resolve inside the app. Dynamic frameworks still need a
Podfile setting, documented in the README.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Reentrant std::make_exception_ptr calls can overwrite the backport’s thread-local metadata and abort the outer capture, affecting arbitrary exception types because the backport replaces generic libc++ entry points.

1 open issue
What changed in this PR

This PR addresses launch crashes on iOS 17 and older when Rive’s React Native integration is built with Xcode 27, caused by Nitro references to newer libc++ exception symbols.

Changes:

  • Adds fallback implementations for two libc++ exception entry points for deployment targets below iOS 18.
  • Documents a Podfile workaround for dynamic frameworks.
  • Adds a reproducer that repeatedly checks native promise rejections.
File Description
README.md Documents the dynamic-framework crash and Podfile workaround.
ios/​LibcxxExceptionPtrBackport.mm Provides exception-pointer fallbacks for older iOS deployment targets.
example/​src/​reproducers/​Issue433ExceptionPtr.tsx Exercises native error conversion and counts expected and unexpected results.

Review effort: Balanced

Comment thread ios/LibcxxExceptionPtrBackport.mm Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The backport can access a destroyed thread-local vector when a destructor calls std::make_exception_ptr during thread shutdown, causing undefined behavior.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread ios/LibcxxExceptionPtrBackport.mm Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The 16-slot array can evict a still-live entry during recursive std::make_exception_ptr calls, causing std::abort() when the outer capture completes even if no constructor throws.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread ios/LibcxxExceptionPtrBackport.mm
The backport is only needed while the Nitro peer range allows releases
without margelo/nitro#1824.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants