Skip to content

[objective_c] NSInputStream can deadlock #3750

Description

@brianquinlan

The NSInputStream returned by toNSInputStream will deadlock if native code calls read:maxLength and the Dart isolate backing it exits before providing any data.

CFNetwork does these reads on its single, process-wide com.apple.NSURLConnectionLoader thread. When it hangs, every NSURLSession request in the process stops, and cancelling tasks can't finish.

The exact code location of the lock being held that will never be released.

To reproduce, add this to pkgs/objective_c/test/ns_input_stream_test.dart:

test('isolate exit while read is blocked', () async {
  final ready = ReceivePort();
  await Isolate.spawn((SendPort sendPort) async {
    final controller = StreamController<List<int>>();
    final stream = controller.stream.toNSInputStream();
    final exitPort = ReceivePort();
    sendPort.send((stream, exitPort.sendPort));
    await exitPort.first;
    Isolate.exit();
  }, ready.sendPort);

  final (isolatedStream, exitSendPort) =
      await ready.first as (NSInputStream, SendPort);
  isolatedStream.open();
  final readFuture = read(isolatedStream, 10);
  await Future<void>.delayed(const Duration(milliseconds: 100));
  exitSendPort.send(null);
  final (count, data, hasBytesAvailable, status, error) =
      await readFuture;
  expect(count, -1);
  expect(data, isEmpty);
  expect(hasBytesAvailable, false);
  expect(status, NSStreamStatus.NSStreamStatusError);
  expect(error, isNotNull);
  isolatedStream.close();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions