Skip to content

[RUM-9753] Fix crash when calling eventEmitter.sendEvent with invalid bridge after Fast Refresh#864

Merged
marco-saia-datadog merged 1 commit into
developfrom
carlosnogueira/RUM-9753/fix-invalid-bridge-crash
May 5, 2025
Merged

[RUM-9753] Fix crash when calling eventEmitter.sendEvent with invalid bridge after Fast Refresh#864
marco-saia-datadog merged 1 commit into
developfrom
carlosnogueira/RUM-9753/fix-invalid-bridge-crash

Conversation

@cdn34dd
Copy link
Copy Markdown
Contributor

@cdn34dd cdn34dd commented Apr 30, 2025

The issue seems to happen when a reference of eventEmitter is kept and used after the RN bridge reference is no longer valid. This mostlikely points to a timing issue, so it's hard to reproduce. The likely cause is related to RN's Fast Refresh feature.

The code follows these simplified steps:

initialize -> enableFeatures -> buildRumConfiguration -> onSessionStart -> eventEmitter.sendEvent(....)
                             -> DatadogSDKWrapper.shared.enableRUM(with: rumConfig)

eventEmitter is never stored directly, but it is captured inside the onSessionStart closure, which means it's retained by the SDK.

When Fast Refresh is used, the code follows these steps:

initialize -> (exit earlier) // -> This is done in order to prevent reinitialization.

But the old onSessionStart closure still remains active and still holds the original reference to the original eventEmitter.

The crash then happens when Datadog's SDK fires onSessionStart closure, because the React Native bridge was destroyed during the Fast Refresh, and the bridge reference present in the original eventEmitter is now invalid.

We can test this by adding a timeout function to the buildRUMConfiguration method that will try to send an event after x seconds, and before that time perform a Fast Refresh. Something like this should do the trick:

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { [weak eventEmitter] in
    guard let emitter = eventEmitter else {
        consolePrint("EventEmitter is nil", .critical)
        return
    }

    if let bridge = emitter.bridge, bridge.isValid {
        consolePrint("Bride is still valid", .debug)
        emitter.sendEvent(withName: "RumSessionStarted", body: [
            "sessionId": "test-session-valid",
            "isDiscarded": false
        ])
    } else {
        consolePrint("Bridge is invalid", .critical)
        emitter.sendEvent(withName: "RumSessionStarted", body: [
            "sessionId": "test-session-invalid",
            "isDiscarded": false
        ])
    }
}

When testing both expo and bare workflows on version 0.77, the behavior seems to differ.

On expo no crash seems to happen, and as expected the .sendEvent also doesn't work, while on bare workflow I could consitentely reproduce the issue as shown below:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error when sending event: RumSessionStarted with body: {
    isDiscarded = 0;
    sessionId = "test-session-invalid";
}. RCTCallableJSModules is not set. This is probably because you've explicitly synthesized the RCTCallableJSModules in DdSdk, even though it's inherited from RCTEventEmitter.'
CoreSimulator 1010.10 - Device: iPhone 16 Pro (1DCFF559-8D78-472F-B80E-BDD380288051) - Runtime: iOS 18.2 (22C150) - DeviceType: iPhone 16 Pro
Can't show file for stack frame : <DBGLLDBStackFrame: 0x39211cbd0> - stackNumber:3 - name:uncaught_exception_handler.cold.1. The file path does not exist on the file system: /Users/runner/work/1/s/Source/PLCrashReporter.m

@cdn34dd cdn34dd requested a review from a team as a code owner April 30, 2025 15:13
@cdn34dd cdn34dd force-pushed the carlosnogueira/RUM-9753/fix-invalid-bridge-crash branch from f83d0c4 to 7b5a540 Compare May 2, 2025 10:33
@datadog-datadog-prod-us1
Copy link
Copy Markdown

Datadog Report

Branch report: carlosnogueira/RUM-9753/fix-invalid-bridge-crash
Commit report: 7b5a540
Test service: dd-sdk-reactnative

✅ 0 Failed, 669 Passed, 1 Skipped, 3.64s Total Time

@cdn34dd cdn34dd changed the title RUM-9753: Fix crash when calling eventEmitter.sendEvent with invalid bridge after Fast Refresh [RUM-9753] Fix crash when calling eventEmitter.sendEvent with invalid bridge after Fast Refresh May 2, 2025
@marco-saia-datadog marco-saia-datadog merged commit ce7bb0f into develop May 5, 2025
8 checks passed
@marco-saia-datadog marco-saia-datadog deleted the carlosnogueira/RUM-9753/fix-invalid-bridge-crash branch May 5, 2025 07:29
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