node/test/parallel/test-process-execve-throws.js
Bryan English 0a9b67e529
process: throw on execve(2) failure instead of aborting
When the underlying execve(2) system call fails, process.execve()
previously printed an error to stderr and called ABORT(), preventing
JS code from detecting or recovering from common failures such as a
missing binary. Throw an ErrnoException instead, carrying the standard
code, errno, syscall, and path properties.

To leave the process in a clean state when execve(2) fails, no longer
run native AtExit callbacks before the call (their in-memory effects
are discarded on success anyway), and snapshot and restore the
FD_CLOEXEC flags on stdio so a failed call has no observable side
effects. Rename and update test-process-execve-abort.js accordingly
and document the new behavior.

Signed-off-by: Bryan English <bryan@bryanenglish.com>
PR-URL: https://github.com/nodejs/node/pull/62878
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-04-27 11:27:39 +00:00

39 lines
1.1 KiB
JavaScript

'use strict';
const common = require('../common');
const assert = require('assert');
const { isMainThread } = require('worker_threads');
if (!isMainThread) {
common.skip('process.execve is not available in Workers');
} else if (common.isWindows || common.isIBMi) {
common.skip('process.execve is not available in Windows or IBM i');
}
assert.throws(
() => {
process.execve(
`${process.execPath}_non_existing`,
[process.execPath, 'arg'],
);
},
(err) => {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOENT');
assert.strictEqual(err.syscall, 'execve');
assert.strictEqual(typeof err.errno, 'number');
assert.ok(err.errno > 0, `expected positive errno, got ${err.errno}`);
assert.match(err.path, /_non_existing$/);
return true;
},
);
assert.strictEqual(process.stdout.writable, true);
assert.strictEqual(process.stderr.writable, true);
assert.strictEqual(typeof process.pid, 'number');
let tickFired = false;
process.nextTick(common.mustCall(() => { tickFired = true; }));
setImmediate(common.mustCall(() => {
assert.strictEqual(tickFired, true);
}));