Compare commits

...

3 Commits

Author SHA1 Message Date
Meghan Denny
87d43696bd Merge branch 'main' into nektro-patch-61014 2025-02-04 18:06:25 -08:00
Meghan Denny
34f37c59c2 Merge branch 'main' into nektro-patch-61014 2025-01-17 15:19:49 -08:00
Meghan Denny
1d3cff2dbc node: add more passing tests 2025-01-03 22:46:24 -08:00
20 changed files with 821 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
'use strict';
// Flags: --expose-gc
const common = require('../common');
const { onGC } = require('../common/gc');
{
onGC({}, { ongc: common.mustCall() });
global.gc();
}
{
onGC(process, { ongc: common.mustNotCall() });
global.gc();
}

View File

@@ -0,0 +1,23 @@
// Flags: --expose-gc
'use strict';
const common = require('../common');
// This test verifies that when a V8 FinalizationRegistryCleanupTask is queue
// at the last moment when JavaScript can be executed, the callback of a
// FinalizationRegistry will not be invoked and the process should exit
// normally.
const reg = new FinalizationRegistry(
common.mustNotCall('This FinalizationRegistry callback should never be called'));
function register() {
// Create a temporary object in a new function scope to allow it to be GC-ed.
reg.register({});
}
process.on('exit', () => {
// This is the final chance to execute JavaScript.
register();
// Queue a FinalizationRegistryCleanupTask by a testing gc request.
global.gc();
});

View File

@@ -0,0 +1,53 @@
'use strict';
const common = require('../common');
if (common.isIBMi)
common.skip('IBMi does not support `fs.watch()`');
// fs-watch on folders have limited capability in AIX.
// The testcase makes use of folder watching, and causes
// hang. This behavior is documented. Skip this for AIX.
if (common.isAIX)
common.skip('folder watch capability is limited in AIX.');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
const testDir = tmpdir.path;
tmpdir.refresh();
// Add a file to newly created folder to already watching folder
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-3');
fs.mkdirSync(testDirectory);
const filePath = path.join(testDirectory, 'folder-3');
const childrenFile = 'file-4.txt';
const childrenAbsolutePath = path.join(filePath, childrenFile);
const childrenRelativePath = path.join(path.basename(filePath), childrenFile);
let watcherClosed = false;
const watcher = fs.watch(testDirectory, { recursive: true });
watcher.on('change', function(event, filename) {
if (filename === childrenRelativePath) {
assert.strictEqual(event, 'rename');
watcher.close();
watcherClosed = true;
}
});
// Do the write with a delay to ensure that the OS is ready to notify us.
setTimeout(() => {
fs.mkdirSync(filePath);
fs.writeFileSync(childrenAbsolutePath, 'world');
}, common.platformTimeout(200));
process.once('exit', function() {
assert(watcherClosed, 'watcher Object was not closed');
});

View File

@@ -0,0 +1,111 @@
'use strict';
const common = require('../common');
const { setTimeout } = require('timers/promises');
if (common.isIBMi)
common.skip('IBMi does not support `fs.watch()`');
// fs-watch on folders have limited capability in AIX.
// The testcase makes use of folder watching, and causes
// hang. This behavior is documented. Skip this for AIX.
if (common.isAIX)
common.skip('folder watch capability is limited in AIX.');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
const testDir = tmpdir.path;
tmpdir.refresh();
(async () => {
// Add a recursive symlink to the parent folder
const testDirectory = fs.mkdtempSync(testDir + path.sep);
// Do not use `testDirectory` as base. It will hang the tests.
const rootDirectory = path.join(testDirectory, 'test-1');
fs.mkdirSync(rootDirectory);
const filePath = path.join(rootDirectory, 'file.txt');
const symlinkFolder = path.join(rootDirectory, 'symlink-folder');
fs.symlinkSync(rootDirectory, symlinkFolder);
if (common.isMacOS) {
// On macOS delay watcher start to avoid leaking previous events.
// Refs: https://github.com/libuv/libuv/pull/4503
await setTimeout(common.platformTimeout(100));
}
const watcher = fs.watch(rootDirectory, { recursive: true });
let watcherClosed = false;
watcher.on('change', function(event, filename) {
assert.ok(event === 'rename', `Received ${event}`);
assert.ok(filename === path.basename(symlinkFolder) || filename === path.basename(filePath), `Received ${filename}`);
if (filename === path.basename(filePath)) {
watcher.close();
watcherClosed = true;
}
});
await setTimeout(common.platformTimeout(100));
fs.writeFileSync(filePath, 'world');
process.once('exit', function() {
assert(watcherClosed, 'watcher Object was not closed');
});
})().then(common.mustCall());
(async () => {
// This test checks how a symlink to outside the tracking folder can trigger change
// tmp/sub-directory/tracking-folder/symlink-folder -> tmp/sub-directory
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const subDirectory = path.join(rootDirectory, 'sub-directory');
fs.mkdirSync(subDirectory);
const trackingSubDirectory = path.join(subDirectory, 'tracking-folder');
fs.mkdirSync(trackingSubDirectory);
const symlinkFolder = path.join(trackingSubDirectory, 'symlink-folder');
fs.symlinkSync(subDirectory, symlinkFolder);
const forbiddenFile = path.join(subDirectory, 'forbidden.txt');
const acceptableFile = path.join(trackingSubDirectory, 'acceptable.txt');
if (common.isMacOS) {
// On macOS delay watcher start to avoid leaking previous events.
// Refs: https://github.com/libuv/libuv/pull/4503
await setTimeout(common.platformTimeout(100));
}
const watcher = fs.watch(trackingSubDirectory, { recursive: true });
let watcherClosed = false;
watcher.on('change', function(event, filename) {
// macOS will only change the following events:
// { event: 'rename', filename: 'symlink-folder' }
// { event: 'rename', filename: 'acceptable.txt' }
assert.ok(event === 'rename', `Received ${event}`);
assert.ok(filename === path.basename(symlinkFolder) || filename === path.basename(acceptableFile), `Received ${filename}`);
if (filename === path.basename(acceptableFile)) {
watcher.close();
watcherClosed = true;
}
});
await setTimeout(common.platformTimeout(100));
fs.writeFileSync(forbiddenFile, 'world');
await setTimeout(common.platformTimeout(100));
fs.writeFileSync(acceptableFile, 'acceptable');
process.once('exit', function() {
assert(watcherClosed, 'watcher Object was not closed');
});
})().then(common.mustCall());

View File

@@ -0,0 +1,81 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const assert = require('assert');
// This test requires the program 'ab'
const http = require('http');
const exec = require('child_process').exec;
const bodyLength = 12345;
const body = 'c'.repeat(bodyLength);
const server = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Length': bodyLength,
'Content-Type': 'text/plain'
});
res.end(body);
});
function runAb(opts, callback) {
const command = `ab ${opts} http://127.0.0.1:${server.address().port}/`;
exec(command, function(err, stdout, stderr) {
if (err) {
if (/ab|apr/i.test(stderr)) {
common.printSkipMessage(`problem spawning \`ab\`.\n${stderr}`);
process.reallyExit(0);
}
throw err;
}
let m = /Document Length:\s*(\d+) bytes/i.exec(stdout);
const documentLength = parseInt(m[1]);
m = /Complete requests:\s*(\d+)/i.exec(stdout);
const completeRequests = parseInt(m[1]);
m = /HTML transferred:\s*(\d+) bytes/i.exec(stdout);
const htmlTransferred = parseInt(m[1]);
assert.strictEqual(bodyLength, documentLength);
assert.strictEqual(completeRequests * documentLength, htmlTransferred);
if (callback) callback();
});
}
server.listen(0, common.mustCall(function() {
runAb('-c 1 -n 10', common.mustCall(function() {
console.log('-c 1 -n 10 okay');
runAb('-c 1 -n 100', common.mustCall(function() {
console.log('-c 1 -n 100 okay');
runAb('-c 1 -n 1000', common.mustCall(function() {
console.log('-c 1 -n 1000 okay');
server.close();
}));
}));
}));
}));

View File

@@ -0,0 +1,44 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const http = require('http');
const server = net.createServer(function(socket) {
// Neither Content-Length nor Connection
socket.end('HTTP/1.1 200 ok\r\n\r\nHello');
}).listen(0, common.mustCall(function() {
http.get({ port: this.address().port }, common.mustCall(function(res) {
let body = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', common.mustCall(function() {
assert.strictEqual(body, 'Hello');
server.close();
}));
}));
}));

View File

@@ -0,0 +1,24 @@
'use strict';
// Flags: --expose-gc
// Check that creating a server without listening does not leak resources.
require('../common');
const { onGC } = require('../common/gc');
const Countdown = require('../common/countdown');
const http = require('http');
const max = 100;
// Note that Countdown internally calls common.mustCall, that's why it's not done here.
const countdown = new Countdown(max, () => {});
for (let i = 0; i < max; i++) {
const server = http.createServer((req, res) => {});
onGC(server, { ongc: countdown.dec.bind(countdown) });
}
setImmediate(() => {
global.gc();
});

View File

@@ -0,0 +1,53 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
// This tests that the http2 server sends data early when it accumulates
// enough from ongoing requests to avoid DoS as mitigation for
// CVE-2019-9517 and CVE-2019-9511.
// Added by https://github.com/nodejs/node/commit/8a4a193
const fixtures = require('../common/fixtures');
const assert = require('assert');
const http2 = require('http2');
const content = fixtures.readSync('person-large.jpg');
const server = http2.createServer({
maxSessionMemory: 1000
});
let streamCount = 0;
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'image/jpeg',
':status': 200
});
stream.end(content);
console.log('server sends content', ++streamCount);
});
server.listen(0, common.mustCall(() => {
const client = http2.connect(`http://localhost:${server.address().port}/`);
let endCount = 0;
let finished = 0;
for (let i = 0; i < 100; i++) {
const req = client.request({ ':path': '/' }).end();
const chunks = [];
req.on('data', (chunk) => {
chunks.push(chunk);
});
req.on('end', common.mustCall(() => {
console.log('client receives content', ++endCount);
assert.deepStrictEqual(Buffer.concat(chunks), content);
if (++finished === 100) {
client.close();
server.close();
}
}));
req.on('error', (e) => {
console.log('client error', e);
});
}
}));

View File

@@ -0,0 +1,27 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const Countdown = require('../common/countdown');
const http2 = require('http2');
const server = http2.createServer();
let session;
const countdown = new Countdown(2, () => {
server.close(common.mustSucceed());
session.close();
});
server.listen(0, common.mustCall(() => {
const client = http2.connect(`http://localhost:${server.address().port}`);
client.on('connect', common.mustCall(() => countdown.dec()));
}));
server.on('session', common.mustCall((s) => {
session = s;
countdown.dec();
}));

View File

@@ -0,0 +1,29 @@
'use strict';
// Flags: --expose-gc
// Check that creating a server without listening does not leak resources.
const common = require('../common');
if (!common.hasCrypto) {
common.skip('missing crypto');
}
const { onGC } = require('../common/gc');
const Countdown = require('../common/countdown');
const https = require('https');
const max = 100;
// Note that Countdown internally calls common.mustCall, that's why it's not done here.
const countdown = new Countdown(max, () => {});
for (let i = 0; i < max; i++) {
const server = https.createServer((req, res) => {});
onGC(server, { ongc: countdown.dec.bind(countdown) });
}
setImmediate(() => {
global.gc();
});

View File

@@ -0,0 +1,45 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const sockets = [];
const server = net.createServer(function(c) {
c.on('close', common.mustCall());
sockets.push(c);
if (sockets.length === 2) {
assert.strictEqual(server.close(), server);
sockets.forEach((c) => c.destroy());
}
});
server.on('close', common.mustCall());
assert.strictEqual(server, server.listen(0, () => {
net.createConnection(server.address().port);
net.createConnection(server.address().port);
}));

View File

@@ -0,0 +1,33 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const server = net.createServer(handle);
const N = 100;
const buf = Buffer.alloc(2, 'a');
server.listen(0, function() {
const conn = net.connect(this.address().port);
conn.on('connect', () => {
let res = true;
let i = 0;
for (; i < N && res; i++) {
conn.cork();
conn.write(buf);
res = conn.write(buf);
conn.uncork();
}
assert.strictEqual(i, N);
conn.end();
});
});
function handle(socket) {
socket.resume();
socket.on('error', common.mustNotCall())
.on('close', common.mustCall(() => server.close()));
}

View File

@@ -0,0 +1,23 @@
'use strict';
// Flags: --expose-gc
require('../common');
const { onGC } = require('../common/gc');
// See https://github.com/nodejs/node/issues/53335
const poller = setInterval(() => {
global.gc();
}, 100);
let count = 0;
for (let i = 0; i < 10; i++) {
const timer = setTimeout(() => {}, 0);
onGC(timer, {
ongc: () => {
if (++count === 10) {
clearInterval(poller);
}
}
});
console.log(+timer);
}

View File

@@ -0,0 +1,38 @@
'use strict';
const common = require('../common');
if (!common.isMainThread)
common.skip("Workers don't have process-like stdio");
// Test if Node handles accessing process.stdin if it is a redirected
// pipe without deadlocking
const { spawn, spawnSync } = require('child_process');
const numTries = 5;
const who = process.argv.length <= 2 ? 'runner' : process.argv[2];
switch (who) {
case 'runner':
for (let num = 0; num < numTries; ++num) {
spawnSync(process.argv0,
[process.argv[1], 'parent'],
{ 'stdio': 'inherit' });
}
break;
case 'parent': {
const middle = spawn(process.argv0,
[process.argv[1], 'middle'],
{ 'stdio': 'pipe' });
middle.stdout.on('data', () => {});
break;
}
case 'middle':
spawn(process.argv0,
[process.argv[1], 'bottom'],
{ 'stdio': [ process.stdin,
process.stdout,
process.stderr ] });
break;
case 'bottom':
process.stdin; // eslint-disable-line no-unused-expressions
break;
}

View File

@@ -0,0 +1,56 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
require('../common');
const assert = require('assert');
// setImmediate should run clear its queued cbs once per event loop turn
// but immediates queued while processing the current queue should happen
// on the next turn of the event loop.
// hit should be the exact same size of QUEUE, if we're letting things
// recursively add to the immediate QUEUE hit will be > QUEUE
let ticked = false;
let hit = 0;
const QUEUE = 10;
function run() {
if (hit === 0) {
setTimeout(() => { ticked = true; }, 1);
const now = Date.now();
while (Date.now() - now < 2);
}
if (ticked) return;
hit += 1;
setImmediate(run);
}
for (let i = 0; i < QUEUE; i++)
setImmediate(run);
process.on('exit', function() {
assert.strictEqual(hit, QUEUE);
});

View File

@@ -0,0 +1,49 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
if (!common.hasIPv6)
common.skip('no IPv6 support');
const assert = require('assert');
const fixtures = require('../common/fixtures');
const tls = require('tls');
const dns = require('dns');
function runTest() {
tls.createServer({
cert: fixtures.readKey('agent1-cert.pem'),
key: fixtures.readKey('agent1-key.pem'),
}).on('connection', common.mustCall(function() {
this.close();
})).listen(0, '::1', common.mustCall(function() {
const options = {
host: 'localhost',
port: this.address().port,
family: 6,
rejectUnauthorized: false,
};
// Will fail with ECONNREFUSED if the address family is not honored.
tls.connect(options).once('secureConnect', common.mustCall(function() {
assert.strictEqual(this.remoteAddress, '::1');
this.destroy();
}));
}));
}
dns.lookup('localhost', {
family: 6, all: true
}, common.mustCall((err, addresses) => {
if (err) {
if (err.code === 'ENOTFOUND' || err.code === 'EAI_AGAIN')
common.skip('localhost does not resolve to ::1');
throw err;
}
if (addresses.some((val) => val.address === '::1'))
runTest();
else
common.skip('localhost does not resolve to ::1');
}));

View File

@@ -0,0 +1,34 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const net = require('net');
const tls = require('tls');
const server = net.createServer((c) => {
c.end();
}).listen(common.mustCall(() => {
const port = server.address().port;
const socket = new net.Socket();
let errored = false;
tls.connect({ socket })
.once('error', common.mustCall((e) => {
assert.strictEqual(e.code, 'ECONNRESET');
assert.strictEqual(e.path, undefined);
assert.strictEqual(e.host, undefined);
assert.strictEqual(e.port, undefined);
assert.strictEqual(e.localAddress, undefined);
errored = true;
server.close();
}))
.on('close', common.mustCall(() => {
assert.strictEqual(errored, true);
}));
socket.connect(port);
}));

View File

@@ -0,0 +1,20 @@
'use strict';
const common = require('../common');
// This test ensures that console.log
// will not crash the process if there
// is not enough space on the V8 stack
const done = common.mustCall();
async function test() {
await test();
}
(async () => {
try {
await test();
} catch (err) {
console.log(err);
}
})().then(done, done);

View File

@@ -0,0 +1,53 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { MessageChannel, Worker } = require('worker_threads');
// Test that SharedArrayBuffer instances created from WASM are transferable
// through MessageChannels (without crashing).
const fixtures = require('../common/fixtures');
const wasmSource = fixtures.readSync('shared-memory.wasm');
const wasmModule = new WebAssembly.Module(wasmSource);
const instance = new WebAssembly.Instance(wasmModule);
const { buffer } = instance.exports.memory;
assert(buffer instanceof SharedArrayBuffer);
{
const { port1, port2 } = new MessageChannel();
port1.postMessage(buffer);
port2.once('message', common.mustCall((buffer2) => {
// Make sure serialized + deserialized buffer refer to the same memory.
const expected = 'Hello, world!';
const bytes = Buffer.from(buffer).write(expected);
const deserialized = Buffer.from(buffer2).toString('utf8', 0, bytes);
assert.deepStrictEqual(deserialized, expected);
}));
}
{
// Make sure we can free WASM memory originating from a thread that already
// stopped when we exit.
const worker = new Worker(`
const { parentPort } = require('worker_threads');
// Compile the same WASM module from its source bytes.
const wasmSource = new Uint8Array([${wasmSource.join(',')}]);
const wasmModule = new WebAssembly.Module(wasmSource);
const instance = new WebAssembly.Instance(wasmModule);
parentPort.postMessage(instance.exports.memory);
// Do the same thing, except we receive the WASM module via transfer.
parentPort.once('message', ({ wasmModule }) => {
const instance = new WebAssembly.Instance(wasmModule);
parentPort.postMessage(instance.exports.memory);
});
`, { eval: true });
worker.on('message', common.mustCall(({ buffer }) => {
assert(buffer instanceof SharedArrayBuffer);
worker.buf = buffer; // Basically just keep the reference to buffer alive.
}, 2));
worker.once('exit', common.mustCall());
worker.postMessage({ wasmModule });
}

View File

@@ -0,0 +1,11 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { Worker } = require('worker_threads');
// Regression for https://github.com/nodejs/node/issues/43182.
const w = new Worker(new URL('data:text/javascript,process.exit(1);await new Promise(()=>{ process.exit(2); })'));
w.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 1);
}));