From d7ed125fd167dad6afc64e05b0bf6a5fee2a35b9 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 15 Jan 2019 14:12:57 -0500 Subject: [PATCH] process: stub unsupported worker methods Some process methods are not supported in workers. This commit adds stubs that throw more informative errors. PR-URL: https://github.com/nodejs/node/pull/25587 Fixes: https://github.com/nodejs/node/issues/25448 Reviewed-By: Anna Henningsen Reviewed-By: Refael Ackermann Reviewed-By: Franziska Hinkelmann Reviewed-By: James M Snell --- lib/internal/bootstrap/node.js | 30 ++++++++++++++-- lib/internal/process/worker_thread_only.js | 10 ++++++ test/parallel/test-process-euid-egid.js | 11 +++--- test/parallel/test-process-initgroups.js | 5 ++- test/parallel/test-process-setgroups.js | 5 ++- test/parallel/test-process-uid-gid.js | 13 +++---- .../test-worker-unsupported-things.js | 34 +++++++++++++------ 7 files changed, 83 insertions(+), 25 deletions(-) diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 2859ebfa444a21..701037cb942ff8 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -84,6 +84,8 @@ if (isMainThread) { } else { const wrapped = workerThreadSetup.wrapProcessMethods(rawMethods); + process.abort = workerThreadSetup.unavailable('process.abort()'); + process.chdir = workerThreadSetup.unavailable('process.chdir()'); process.umask = wrapped.umask; } @@ -148,6 +150,14 @@ if (credentials.implementsPosixCredentials) { process.seteuid = wrapped.seteuid; process.setgid = wrapped.setgid; process.setuid = wrapped.setuid; + } else { + process.initgroups = + workerThreadSetup.unavailable('process.initgroups()'); + process.setgroups = workerThreadSetup.unavailable('process.setgroups()'); + process.setegid = workerThreadSetup.unavailable('process.setegid()'); + process.seteuid = workerThreadSetup.unavailable('process.seteuid()'); + process.setgid = workerThreadSetup.unavailable('process.setgid()'); + process.setuid = workerThreadSetup.unavailable('process.setuid()'); } } @@ -174,8 +184,24 @@ if (config.hasInspector) { // This attaches some internal event listeners and creates: // process.send(), process.channel, process.connected, // process.disconnect() -if (isMainThread && process.env.NODE_CHANNEL_FD) { - mainThreadSetup.setupChildProcessIpcChannel(); +if (process.env.NODE_CHANNEL_FD) { + if (ownsProcessState) { + mainThreadSetup.setupChildProcessIpcChannel(); + } else { + Object.defineProperty(process, 'channel', { + enumerable: false, + get: workerThreadSetup.unavailable('process.channel') + }); + + Object.defineProperty(process, 'connected', { + enumerable: false, + get: workerThreadSetup.unavailable('process.connected') + }); + + process.send = workerThreadSetup.unavailable('process.send()'); + process.disconnect = + workerThreadSetup.unavailable('process.disconnect()'); + } } const browserGlobals = !process._noBrowserGlobals; diff --git a/lib/internal/process/worker_thread_only.js b/lib/internal/process/worker_thread_only.js index f05d5e932bebf2..2cc52cbf01b8cd 100644 --- a/lib/internal/process/worker_thread_only.js +++ b/lib/internal/process/worker_thread_only.js @@ -45,7 +45,17 @@ function wrapProcessMethods(binding) { return { umask }; } +function unavailable(name) { + function unavailableInWorker() { + throw new ERR_WORKER_UNSUPPORTED_OPERATION(name); + } + + unavailableInWorker.disabled = true; + return unavailableInWorker; +} + module.exports = { initializeWorkerStdio, + unavailable, wrapProcessMethods }; diff --git a/test/parallel/test-process-euid-egid.js b/test/parallel/test-process-euid-egid.js index 5639163bf31c13..b9e0630dab5eca 100644 --- a/test/parallel/test-process-euid-egid.js +++ b/test/parallel/test-process-euid-egid.js @@ -3,16 +3,17 @@ const common = require('../common'); const assert = require('assert'); -if (common.isWindows || !common.isMainThread) { - if (common.isMainThread) { - assert.strictEqual(process.geteuid, undefined); - assert.strictEqual(process.getegid, undefined); - } +if (common.isWindows) { + assert.strictEqual(process.geteuid, undefined); + assert.strictEqual(process.getegid, undefined); assert.strictEqual(process.seteuid, undefined); assert.strictEqual(process.setegid, undefined); return; } +if (!common.isMainThread) + return; + assert.throws(() => { process.seteuid({}); }, { diff --git a/test/parallel/test-process-initgroups.js b/test/parallel/test-process-initgroups.js index 49b8833f61a7bc..f5e839b1d242af 100644 --- a/test/parallel/test-process-initgroups.js +++ b/test/parallel/test-process-initgroups.js @@ -2,11 +2,14 @@ const common = require('../common'); const assert = require('assert'); -if (common.isWindows || !common.isMainThread) { +if (common.isWindows) { assert.strictEqual(process.initgroups, undefined); return; } +if (!common.isMainThread) + return; + [undefined, null, true, {}, [], () => {}].forEach((val) => { assert.throws( () => { diff --git a/test/parallel/test-process-setgroups.js b/test/parallel/test-process-setgroups.js index a85d6683164a26..74de3e7a2562e7 100644 --- a/test/parallel/test-process-setgroups.js +++ b/test/parallel/test-process-setgroups.js @@ -2,11 +2,14 @@ const common = require('../common'); const assert = require('assert'); -if (common.isWindows || !common.isMainThread) { +if (common.isWindows) { assert.strictEqual(process.setgroups, undefined); return; } +if (!common.isMainThread) + return; + assert.throws( () => { process.setgroups(); diff --git a/test/parallel/test-process-uid-gid.js b/test/parallel/test-process-uid-gid.js index 456cba7f4dc027..49086792b9e7b1 100644 --- a/test/parallel/test-process-uid-gid.js +++ b/test/parallel/test-process-uid-gid.js @@ -24,17 +24,18 @@ const common = require('../common'); const assert = require('assert'); -if (common.isWindows || !common.isMainThread) { - // uid/gid functions are POSIX only, setters are main-thread only. - if (common.isMainThread) { - assert.strictEqual(process.getuid, undefined); - assert.strictEqual(process.getgid, undefined); - } +if (common.isWindows) { + // uid/gid functions are POSIX only. + assert.strictEqual(process.getuid, undefined); + assert.strictEqual(process.getgid, undefined); assert.strictEqual(process.setuid, undefined); assert.strictEqual(process.setgid, undefined); return; } +if (!common.isMainThread) + return; + assert.throws(() => { process.setuid({}); }, { diff --git a/test/parallel/test-worker-unsupported-things.js b/test/parallel/test-worker-unsupported-things.js index 66b10ad1577d2c..cc9eec4af67760 100644 --- a/test/parallel/test-worker-unsupported-things.js +++ b/test/parallel/test-worker-unsupported-things.js @@ -1,9 +1,12 @@ 'use strict'; const common = require('../common'); const assert = require('assert'); -const { Worker, isMainThread, parentPort } = require('worker_threads'); +const { Worker, parentPort } = require('worker_threads'); -if (isMainThread) { +// Do not use isMainThread so that this test itself can be run inside a Worker. +if (!process.env.HAS_STARTED_WORKER) { + process.env.HAS_STARTED_WORKER = 1; + process.env.NODE_CHANNEL_FD = 'foo'; // Make worker think it has IPC. const w = new Worker(__filename); w.on('message', common.mustCall((message) => { assert.strictEqual(message, true); @@ -21,14 +24,25 @@ if (isMainThread) { assert.strictEqual(process.debugPort, before); } - assert.strictEqual('abort' in process, false); - assert.strictEqual('chdir' in process, false); - assert.strictEqual('setuid' in process, false); - assert.strictEqual('seteuid' in process, false); - assert.strictEqual('setgid' in process, false); - assert.strictEqual('setegid' in process, false); - assert.strictEqual('setgroups' in process, false); - assert.strictEqual('initgroups' in process, false); + const stubs = ['abort', 'chdir', 'send', 'disconnect']; + + if (!common.isWindows) { + stubs.push('setuid', 'seteuid', 'setgid', + 'setegid', 'setgroups', 'initgroups'); + } + + stubs.forEach((fn) => { + assert.strictEqual(process[fn].disabled, true); + assert.throws(() => { + process[fn](); + }, { code: 'ERR_WORKER_UNSUPPORTED_OPERATION' }); + }); + + ['channel', 'connected'].forEach((fn) => { + assert.throws(() => { + process[fn]; + }, { code: 'ERR_WORKER_UNSUPPORTED_OPERATION' }); + }); assert.strictEqual('_startProfilerIdleNotifier' in process, false); assert.strictEqual('_stopProfilerIdleNotifier' in process, false);