worker: handle detached MessagePort from a different context

When `worker.moveMessagePortToContext` is used, the async handle
associated with the port, will be triggered more than needed (at least
one more time) and with null data. That can be avoided by simply
checking that the data is present and the port is not detached.

Fixes: https://github.com/nodejs/node/issues/49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/49150
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
Juan José authored and GitHub committed 2023-10-22 21:20:52 +00:00
1 parent a58ffad656
commit c206b2a8a4
2 files changed
+35 -2

No files matched your search

+7
View File
@@ -789,6 +789,13 @@ MaybeLocal<Value> MessagePort::ReceiveMessage(Local<Context> context,
void MessagePort::OnMessage(MessageProcessingMode mode) {
Debug(this, "Running MessagePort::OnMessage()");
// Maybe the async handle was triggered empty or more than needed.
// The data_ could be freed or, the handle has been/is being closed.
// A possible case for this, is transfer the MessagePort to another
// context, it will call the constructor and trigger the async handle empty.
// Because all data was sent from the preivous context.
if (IsDetached()) return;
HandleScope handle_scope(env()->isolate());
Local<Context> context =
object(env()->isolate())->GetCreationContext().ToLocalChecked();
@@ -1,11 +1,11 @@
'use strict';
require('../common');
const assert = require('assert');
const assert = require('node:assert');
const {
Worker, MessageChannel
} = require('worker_threads');
} = require('node:worker_threads');
const channel = new MessageChannel();
const workerData = { mesage: channel.port1 };
@@ -61,3 +61,29 @@ const meowScript = () => 'meow';
'listed in transferList'
});
}
{
// Should not crash when MessagePort is transferred to another context.
// https://github.com/nodejs/node/issues/49075
const channel = new MessageChannel();
new Worker(`
const { runInContext, createContext } = require('node:vm')
const { workerData } = require('worker_threads');
const context = createContext(Object.create(null));
context.messagePort = workerData.messagePort;
runInContext(
\`messagePort.postMessage("Meow")\`,
context,
{ displayErrors: true }
);
`, {
eval: true,
workerData: { messagePort: channel.port2 },
transferList: [channel.port2]
});
channel.port1.on(
'message',
(message) =>
assert.strictEqual(message, 'Meow')
);
}