Skip to content

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

Closed
@corrideat

Description

@corrideat

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

Metadata

Metadata

Assignees

Labels

confirmed-bugIssues with confirmed bugs.workerIssues and PRs related to Worker support.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions