Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions test/parallel/test-worker-message-port-transfer-filehandle-fd0.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
'use strict';

// A FileHandle whose transfer is discarded has to close its file descriptor.
// Descriptor 0 is an ordinary descriptor once stdin has been closed, so the
// scenario runs in a child process that can afford to lose its stdin.
// A FileHandle whose transfer is discarded has to close its file descriptor,
// descriptor 0 included. The child gets this file as stdin, so descriptor 0
// refers to it from the start and no other thread can take it before the
// child wraps it in a FileHandle. The child can afford to lose its stdin.

const common = require('../common');

if (common.isWindows)
common.skip('descriptor numbering after closing stdin is POSIX-specific');
common.skip('libuv does not close descriptors 0 to 2 on Windows');

const assert = require('assert');
const fs = require('fs');
Expand All @@ -16,11 +17,13 @@ if (process.argv[2] === 'child') {
const vm = require('vm');
const { MessageChannel, moveMessagePortToContext } =
require('worker_threads');
const { internalBinding } = require('internal/test/binding');
const { FileHandle } = require('internal/fs/promises');
const { FileHandle: NativeFileHandle } = internalBinding('fs');

(async function() {
fs.closeSync(0);
const fh = await fs.promises.open(__filename);
assert.strictEqual(fh.fd, 0);
const { dev, ino } = fs.fstatSync(0, { bigint: true });
const fh = new FileHandle(new NativeFileHandle(0));

const { port1, port2 } = new MessageChannel();
// A port living in another context cannot receive the handle, so the
Expand All @@ -34,13 +37,24 @@ if (process.argv[2] === 'child') {
port1.postMessage(fh, [ fh ]);
await discarded;

assert.throws(() => fs.fstatSync(0), { code: 'EBADF' });
// Another thread may already have reused descriptor 0, but not for this
// file.
let stats;
try {
stats = fs.fstatSync(0, { bigint: true });
} catch (err) {
assert.strictEqual(err.code, 'EBADF');
}
if (stats)
assert.notDeepStrictEqual([stats.dev, stats.ino], [dev, ino]);
port1.close();
})().then(common.mustCall());
return;
}

const { spawnSync } = require('child_process');
const result = spawnSync(process.execPath, [ __filename, 'child' ],
{ stdio: [ 'ignore', 'inherit', 'inherit' ] });
assert.strictEqual(result.status, 0);
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
const fd = fs.openSync(__filename);
spawnSyncAndExitWithoutError(process.execPath,
[ '--expose-internals', __filename, 'child' ],
{ stdio: [ fd, 'inherit', 'inherit' ] });
fs.closeSync(fd);
Loading