Skip to content

PaymobSDK.xcframework embeds a private copy of Sentry Cocoa, causing crashes when host app also uses Sentry #2

Description

@devmfouad

Summary

PaymobSDK.xcframework (iOS) statically embeds its own private copy of the
Sentry Cocoa SDK inside its binary. Any host app that also integrates Sentry
(directly, or via sentry_flutter for Flutter apps) ends up with two
different images in the same process both defining Objective-C/Swift classes
with the same names (SentrySDKInternal, SentryExperimentalOptions, etc.).
Because Objective-C classes are uniqued by name per-process, the runtime
resolves calls to whichever copy "wins" the uniquing race — which is often
not the caller's own copy. This causes a crash on app launch as soon as the
host app's Sentry SDK initializes.

Environment

  • PaymobSDK version: 1.3.2 (PaymobSDK.xcframework, vendored binary framework)
  • Host app: Flutter, using sentry_flutter: 9.22.0 (native sentry-cocoa 8.58.3)
  • Platform: iOS (reproduced on iOS Simulator; Xcode 17 / iOS 26 toolchain)
  • Integration: Flutter's Swift Package Manager plugin support for
    sentry_flutter (native Sentry linked via SPM), PaymobSDK integrated via
    CocoaPods vendored_frameworks

Note: we confirmed this is not specific to our integration method. The
official flutter_paymob_sdk Flutter plugin
(https://github.com/PaymobAccept/flutter_sdk) vendors the identical
PaymobSDK.xcframework binary (ios/Frameworks/PaymobSDK.xcframework in
that repo) — so any app using the official plugin alongside Sentry would hit
the same conflict. This is a problem in the PaymobSDK.xcframework binary
itself, not in how a given app wires it up.

Steps to reproduce

  1. Integrate PaymobSDK.xcframework 1.3.2 into an iOS app.
  2. Integrate any version of Sentry's iOS SDK (directly, or via sentry_flutter)
    in the same app, and call SentrySDK.start / SentryFlutter.init during
    app launch.
  3. Do a fully clean build (clear DerivedData, SwiftPM package cache,
    and Pods) so both frameworks are freshly linked from scratch.
  4. Launch the app.

Expected behavior

The app launches normally; both SDKs operate independently.

Actual behavior

The app crashes on launch. We reproduced two distinct crash signatures
depending on how our own Sentry copy is linked (static vs. dynamic) — both
stemming from the same root cause:

A) Our Sentry statically linked (default sentry_flutter configuration):

Could not cast value of type 'Sentry.SentryExperimentalOptions' (0x102af3800)
to 'Sentry.SentryExperimentalOptions' (0x101de55e0).

Swift's runtime detects two non-identical type metadata records for what
should be the same type and traps.

B) Our Sentry linked as a dynamic framework (Sentry-Dynamic product) —
tried as a workaround, made things worse rather than better:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000001

Backtrace (trimmed):

SentryFlutterPlugin.handle(_:result:)
SentryFlutterPlugin.initNativeSdk(_:result:)
+[SentrySDKInternal startWithConfigureOptions:]   <-- resolved into PaymobSDK.framework's image, not ours
SentryFlutter.update(options:with:)
swift_beginAccess

In this case, our own plugin code (built against our Sentry's expected
object layout) called +[SentrySDKInternal startWithConfigureOptions:], but
the Objective-C runtime resolved that class to PaymobSDK.framework's own
embedded copy
instead of ours, since both images define a class with that
exact name. Calling into the wrong implementation with an object built for
the other one's layout corrupts memory and segfaults.

Root cause evidence

Running strings on PaymobSDK.xcframework's binary shows it contains
Sentry's own source paths and mangled Swift symbols, confirming Sentry is
statically embedded inside PaymobSDK itself:

Sentry SDK was loaded multiple times in the same binary
/Users/runner/work/sentry-cocoa/sentry-cocoa/Sources/Sentry/Processors/SentryWatchdogTerminationBreadcrumbProcessor.m
/Users/runner/work/sentry-cocoa/sentry-cocoa/Sources/Sentry/Profiling/SentryContinuousProfiler.mm
$s6Sentry0A12MaskRendererP
$s6Sentry0A13RedactOptionsP
...

Notably, the string "Sentry SDK was loaded multiple times in the same binary" is Sentry's own internal guard message for exactly this scenario —
this conflict is a known failure mode for the Sentry SDK itself, not
something specific to our integration.

Why this is a PaymobSDK issue, not something we can fix on our side

  • We tried both static and dynamic linking for our own Sentry copy; both
    crash, because the fundamental problem is two copies of Sentry's classes
    existing in one process, not how either copy is linked.
  • We cannot rename, strip, or otherwise patch symbols inside a closed-source,
    vendored .xcframework we don't control.
  • Removing Sentry from our own app entirely is not an acceptable workaround —
    it would mean losing crash reporting for the whole app just to
    accommodate a payment SDK.

Requested fix

Please ship a build of PaymobSDK.xcframework that does not statically
embed its own copy of Sentry — either by removing the Sentry dependency
entirely, or by properly namespacing/isolating it (e.g. via symbol hiding /
-fvisibility=hidden for embedded third-party dependencies, or dynamic
linking with a private install name) so it cannot collide with a host app's
own Sentry integration.

Happy to provide the full .ips crash report, a minimal repro project, or
test a candidate fix build — please let us know what would help.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions