Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation Fault on Contextifying MessagePort Transferred to a Worker Thread #49075

Closed
corrideat opened this issue Aug 9, 2023 · 2 comments · Fixed by #49150
Closed

Segmentation Fault on Contextifying MessagePort Transferred to a Worker Thread #49075

corrideat opened this issue Aug 9, 2023 · 2 comments · Fixed by #49150
Assignees
Labels
confirmed-bug Issues with confirmed bugs. worker Issues and PRs related to Worker support.

Comments

@corrideat
Copy link

corrideat commented Aug 9, 2023

Version

  • v17.1.0
  • v18.14.2
  • v19.9.0

Platform

  • Linux WORKSTATION 5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
  • Microsoft Windows NT 10.0.19045.0 x64

Subsystem

vm, maybe node:internal/per_context

What steps will reproduce the bug?

  1. Create a MessagePort
  2. Create a Worker and transfer the message port to the worker.
  3. Create a VM context and contextify the message port
  4. (Sometimes) Attempt to access the contextified message port

Sample code to reproduce

/* eslint-disable */
const { Worker } = require('node:worker_threads');

const messageChannel = new MessageChannel();

const text = `
const vm = require('node:vm');
const {
	isMainThread,
	moveMessagePortToContext,
	workerData,
} = require('node:worker_threads');

const context = Object.create(null);

context.console = console;

vm.createContext(context, {
    codeGeneration: {
        strings: false,
        wasm: false,
    },
});

console.log('[WT] messagePort ctor:', workerData.messagePort.constructor.name);

const messageChannel = new MessageChannel();
messageChannel.port1.onmessage = (ev) => {
	console.log('[WT] RECV MSG', ev.data);
	messageChannel.port1.close();
};

context.messagePort = moveMessagePortToContext(
    workerData.crash ? workerData.messagePort : messageChannel.port2,
    context,
);

// This vm.runInContext doesn't seem entirely necessary to trigger the crash
// Sometimes just accessing the properties of 'messagePort' is required
vm.runInContext(
    \`
        console.log("[VM] Started");
        messagePort.postMessage("Hello, World!")
    \`,
    context,
    { displayErrors: true }
);
`;

// Change this to false to avoid crashing
// NOTE: Just transferring the MessagePort to the worker,
// without contextifying, or even using it from the worker
// does NOT trigger a crash and works as expected.
const crash = true;

new Worker(text, {
	workerData: {
		crash,
		messagePort: messageChannel.port2,
	},
	env: Object.create(null),
	eval: true,
	transferList: [messageChannel.port2],
});

if (crash) {
	messageChannel.port1.onmessage = (ev) => {
		console.log('[MAIN] RECV MSG', ev.data);
		messageChannel.port1.close();
	};
}

How often does it reproduce? Is there a required condition?

It always reproduces. It sometimes (on Node 18 on Windows, apparently) requires accessing a property in the contextified port. Otherwise just contextifying the port is enough.

What is the expected behavior? Why is that the expected behavior?

The port is contextified and usable, even across multiple contexts. At worst, an error should occur without crashing or aborting the Node process.

What do you see instead?

Node crashes with a segmentation fault.

Sample output (Node 17)

[WT] messagePort ctor: MessagePort
[MAIN] RECV MSG Hello, World!
[VM] Started

Command terminated by signal 11

Sample output (Node 18)

[WT] messagePort ctor: MessagePort

Sample output (Node 19)

[WT] messagePort ctor: MessagePort
[MAIN] RECV MSG Hello, World!
[VM] Started
[1]    4551 segmentation fault  node sample.js

Additional information

No response

@juanarbol juanarbol self-assigned this Aug 9, 2023
@juanarbol juanarbol added the confirmed-bug Issues with confirmed bugs. label Aug 9, 2023
@juanarbol
Copy link
Member

Hey! Thanks for the report, and the repro case is really good, I'm gonna work on this one :-)

@debadree25 debadree25 added the worker Issues and PRs related to Worker support. label Aug 9, 2023
@juanarbol
Copy link
Member

The problem seems to be the moveMessagePortToContext call, the crash is gone by doing this:

context.messagePort = workerData.crash ? workerData.messagePort : messageChannel.port2

I'm investigating a bit more, and send a possible fix for this one

juanarbol added a commit to juanarbol/node that referenced this issue Aug 13, 2023
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: nodejs#49075
juanarbol added a commit to juanarbol/node that referenced this issue Aug 13, 2023
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: nodejs#49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
juanarbol added a commit to juanarbol/node that referenced this issue Aug 13, 2023
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: nodejs#49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
juanarbol added a commit to juanarbol/node that referenced this issue Aug 13, 2023
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: nodejs#49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
juanarbol added a commit to juanarbol/node that referenced this issue Aug 23, 2023
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: nodejs#49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
juanarbol added a commit to juanarbol/node that referenced this issue Aug 24, 2023
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: nodejs#49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
juanarbol added a commit to juanarbol/node that referenced this issue Aug 29, 2023
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: nodejs#49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
nodejs-github-bot pushed a commit that referenced this issue Oct 22, 2023
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: #49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
PR-URL: #49150
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
targos pushed a commit that referenced this issue Oct 23, 2023
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: #49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
PR-URL: #49150
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
alexfernandez pushed a commit to alexfernandez/node that referenced this issue Nov 1, 2023
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: nodejs#49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
PR-URL: nodejs#49150
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
targos pushed a commit that referenced this issue Nov 11, 2023
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: #49075
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
PR-URL: #49150
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug Issues with confirmed bugs. worker Issues and PRs related to Worker support.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants