Skip to content

CallbackProxies dereferences JNI local refs on another thread #1

Description

@krassx

Found while moving Android's report-handler dispatch off the main thread (bugsee-android#146). Latent today only because that dispatch ran inline on the main thread — once handlers run on a background thread, this becomes a live JNI misuse.

The defect

CallbackProxies.cs:54-117 enqueues the JNI references for report and completion onto a queue drained later in Unity's Update(). Those are local references: the JNI spec only guarantees them for the duration of the native call that produced them. Dereferencing them from another thread, after the proxy method has returned, is undefined behaviour — in practice a crash or a silently wrong object once the local frame is popped.

EventFilterProxy.filter has the same shape.

Why it has not bitten yet

Android dispatched report handlers on the main thread and, on the dialog-submit path, inline in the caller's frame. Unity's Update() runs on that same thread, so the drain happened to occur while the frame was still live. That is luck, not correctness — and bugsee-android#146 removes it by dispatching handlers on a dedicated background thread.

Fix

Either promote to global references (NewGlobalRef on enqueue, DeleteGlobalRef after the drain — with care not to leak if the queue is discarded), or use MainThreadDispatcher.RunSync so the dereference happens before the proxy call returns and the local frame is still valid.

The second is simpler but reintroduces a main-thread hop, which is the thing Android just removed — so on a wedged main thread the handler would not run. Global refs keep the benefit.

Scope

cross/bugsee-unity (UPM package, branch cursor/upm-package-scaffold) — not shipped, so there is no released version affected. The legacy cross/unity wrapper registers only metadata and does not implement ReportHandler, so it is unaffected.

Verified unaffected for the same change: Flutter (hops to main itself), .NET and KMP (run the host callback inline, no Handler/UI calls), React Native / Capacitor / Cordova (do not implement ReportHandler).

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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