Skip to content

TypeScript shim: record notifier can be called after the host dropped it #540

Description

@sargunv-bot

Where

bindings/typescript/host-support/src/mln_abi.c, mln_abi_queue_push.

What

The notifier and its user data are read under the queue lock, then called
outside it:

    notify = owner->notify;
    notify_data = owner->notify_data;
  }
  mln_abi_queue_release();
  ...
  /* Outside the lock: the notifier reaches the host's runtime, which must not
   * be able to deadlock against a producer. */
  if (notify != NULL) {
    notify(notify_data);

Calling outside the lock is deliberate and correct — a notifier reaches the
host's runtime and must not be able to deadlock against a producer. The gap is
that nothing keeps notify_data alive across that window.

A host that stops notifications between the read and the call drops the state
notify_data points at while a producer is about to dereference it. On the
Node-API transport that state is a boxed threadsafe function; the window is
small but a producer thread is MapLibre's, not the host's, so nothing
serialises them.

Impact

Use-after-free reachable from ordinary teardown: clearing a callback, closing
a Maplibre context, or a worker exiting while MapLibre is still delivering.

Not observed in the suite — found by reading during the owner-token work
(#PR). It predates that change and has the same shape now, per owner rather
than process-global.

Scope

TypeScript only. This queue lives in the TypeScript host-support shim; the
shared src/c_api/callback_adapter.cpp has no equivalent notifier, so Dart and
the other bindings that use the C API directly are unaffected.

Fixing it

Needs the notifier to outlive the call — refcount the registration and release
it after notify returns, or hold a grace period on stop that waits for
in-flight pushes. Out of scope for the change that found it.

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