Skip to content

Ports shared through IsolateNameServer have unexpected behavior #147469

@iazel

Description

@iazel

Steps to reproduce

  1. Register a port through IsolateNameServer.registerPortWithName
  2. Either don't listen on the port, or close the port, or Isolate.kill() the given isolate
  3. Retrieve the port through IsolateNameServer.lookupPortByName
  4. Send a custom class through send

Please be aware that it is important to send a custom class, otherwise the issue does not exist.

Another interesting aspect is that if we get port before it is closed, and keep using it, then no issue arise.

Expected results

Ports normally exhibit the following behavior:

  • Messages sent to a port that isn't ready (i.e. not listening), will be delivered as soon as listen is called
  • Sending messages to a closed port is a no-op
  • Data can be sent according to documentation, including the same-code ones

Actual results

When using data types supported across different code-bases (e.g: int, string, etc...), no issues arise.

When using data types supported only on same code-bases (e.g. custom classes), then ArgumentError is thrown on port.send if the receiving end is somehow closed or not ready.

Code sample

Code sample
import 'dart:isolate';
import 'dart:ui';

import 'package:flutter_test/flutter_test.dart';

final class A {
}

void main() {
  test('isolate', () async {
    TestWidgetsFlutterBinding.ensureInitialized();
    await Isolate.spawn(
      (_) {
        final port = ReceivePort();
        port.listen((_) {
          Isolate.exit();
        });
        IsolateNameServer.registerPortWithName(port.sendPort, 'test');
      },
      null,
    );

    while (IsolateNameServer.lookupPortByName('test') == null) {
      await Future<void>.delayed(const Duration(milliseconds: 100));
    }

    for (var i = 0; i < 10; ++i) {
      IsolateNameServer.lookupPortByName('test')?.send(A());
      await Future<void>.delayed(const Duration(milliseconds: 100));
    }
  });
}

Screenshots or Video

No response

Logs

Logs
dart:isolate                  _SendPort.send
test/isolate_test.dart 28:51  main.<fn>

Invalid argument: is a regular instance reachable via : Instance of 'A'

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.19.6, on Ubuntu 23.10 6.5.0-28-generic, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Android Studio (version 2023.2)
[✓] IntelliJ IDEA Community Edition (version 2023.3)
[✓] Connected device (2 available)
[✓] Network resources

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority issues at the top of the work listdependency: dartDart team may need to help usdependency:dart-triagedTriaged by Dart teamengineflutter/engine related. See also e: labels.found in release: 3.19Found to occur in 3.19found in release: 3.22Found to occur in 3.22has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions