Skip to content

Closures in FieldInfo make it impossible to send some message representations to isolates  #167

Closed
@timburks

Description

@timburks

I got the following error message when I tried to send a protobuf message to an isolate:

Unhandled exception:
Invalid argument(s): Illegal argument in isolate message : (object is a closure - Function '<anonymous closure>':.)
#0      _SendPortImpl._sendInternal (dart:isolate/runtime/libisolate_patch.dart:218:70)
#1      _SendPortImpl.send (dart:isolate/runtime/libisolate_patch.dart:202:5)
#2      sendReceive (file:///Users/tim/Desktop/DART/messages/bin/printer.dart:40:8)
#3      main (file:///Users/tim/Desktop/DART/messages/bin/printer.dart:54:3)
<asynchronous suspension>
#4      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:287:32)
#5      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)

This surprised me because I had previously been able to send other message representations. Looking more closely, I found that the error only occurred for my messages with repeated fields, and looking into the representation of FieldInfo I think I see why: because this field and the ones following it store functions for various special cases, including repeated fields.

Here is my test program:

import 'dart:async';
import 'dart:isolate';

import 'package:printer/src/generated/sample.pb.dart';

// Runs in a separate thread.
void printer(SendPort listener) async {
  // create receive port and send it to the listener
  var receivePort = new ReceivePort();
  listener.send(receivePort.sendPort);
  
  // listen on receive port for things to print
  await for (var msg in receivePort) {
    print('>> [${msg[0]}] (${msg[0].runtimeType})');
	var replyPort = msg[1];
	replyPort.send(null);
  }
}

/// sends a message on a port, 
/// receives the response,
/// and returns a future for the message that was received
Future sendReceive(SendPort port, msg) {
  var response = new ReceivePort();
  port.send([msg, response.sendPort]);
  return response.first;
}

main(List<String> args) async {
  // Start the printer and wait for it to reply with its SendPort.
  var receivePort = new ReceivePort();
  Isolate.spawn(printer, receivePort.sendPort);
  var  p = await receivePort.first;

  // Send some things
  sendReceive(p, 123);
  sendReceive(p, "hello");
  sendReceive(p, Kiosk());
  sendReceive(p, SetSignIdForKioskIdsRequest());
}

My protos are in sample.proto:

syntax = "proto3";

package sample;

// Describes a hardware device that can display signs.
message Kiosk {
  int32 id = 1;                       // unique id
  string name = 2;                    // name of device hardware
  ScreenSize size = 3;                // screen size
}

// Represents the size of a screen in pixels.
message ScreenSize {
  int32 width = 1;                    // screen width
  int32 height = 2;                   // screen height
}

message SetSignIdForKioskIdsRequest {
  repeated int32 kiosk_ids = 1;
  int32 sign_id = 2;
}

When I remove the repeated keyword from the kiosks_ids field in my proto, my test program runs successfully:

dart bin/printer.dart 
>> [123] (int)
>> [hello] (String)
>> [] (Kiosk)
>> [] (SetSignIdForKioskIdsRequest)

I'm new to Dart, so I'm not sure that sending structs into isolates is a good practice (due to possible efficiency problems), but it seems bad for this to work for some protobuf messages and not others.

Metadata

Metadata

Assignees

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