diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 5e313628ff..e979eed33e 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -2430,6 +2430,22 @@ JSC_DEFINE_CUSTOM_SETTER(setProcessExecArgv, (JSGlobalObject * globalObject, Enc return true; } +JSC_DEFINE_CUSTOM_GETTER(processGetEval, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + Process* process = getProcessObject(globalObject, JSValue::decode(thisValue)); + if (!process) { + return JSValue::encode(jsUndefined()); + } + + return Bun__Process__getEval(globalObject); +} + +JSC_DEFINE_CUSTOM_SETTER(setProcessGetEval, (JSGlobalObject * globalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName)) +{ + // dont allow setting eval from js + return true; +} + static JSValue constructBrowser(VM& vm, JSObject* processObject) { return jsBoolean(false); @@ -3722,6 +3738,7 @@ extern "C" void Process__emitErrorEvent(Zig::GlobalObject* global, EncodedJSValu @begin processObjectTable _debugEnd Process_stubEmptyFunction Function 0 _debugProcess Process_stubEmptyFunction Function 0 + _eval processGetEval CustomAccessor _fatalException Process_stubEmptyFunction Function 1 _getActiveHandles Process_stubFunctionReturningArray Function 0 _getActiveRequests Process_stubFunctionReturningArray Function 0 diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index cfbb1c7f81..c41dda57be 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -629,6 +629,7 @@ ZIG_DECL JSC::EncodedJSValue Bun__Process__getExecPath(JSC::JSGlobalObject* arg0 ZIG_DECL void Bun__Process__getTitle(JSC::JSGlobalObject* arg0, ZigString* arg1); ZIG_DECL JSC::EncodedJSValue Bun__Process__setCwd(JSC::JSGlobalObject* arg0, ZigString* arg1); ZIG_DECL JSC::EncodedJSValue Bun__Process__setTitle(JSC::JSGlobalObject* arg0, ZigString* arg1); +ZIG_DECL JSC::EncodedJSValue Bun__Process__getEval(JSC::JSGlobalObject* arg0); #endif CPP_DECL ZigException ZigException__fromException(JSC::Exception* arg0); diff --git a/src/bun.js/node/node_process.zig b/src/bun.js/node/node_process.zig index 7647189c26..f30e60cd23 100644 --- a/src/bun.js/node/node_process.zig +++ b/src/bun.js/node/node_process.zig @@ -9,6 +9,7 @@ comptime { @export(&createArgv0, .{ .name = "Bun__Process__createArgv0" }); @export(&getExecPath, .{ .name = "Bun__Process__getExecPath" }); @export(&createExecArgv, .{ .name = "Bun__Process__createExecArgv" }); + @export(&getEval, .{ .name = "Bun__Process__getEval" }); } var title_mutex = bun.Mutex{}; @@ -193,6 +194,14 @@ pub fn getExecArgv(global: *JSGlobalObject) callconv(.c) JSValue { return Bun__Process__getExecArgv(global); } +pub fn getEval(globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue { + const vm = globalObject.bunVM(); + if (vm.module_loader.eval_source) |source| { + return JSC.ZigString.init(source.contents).toJS(globalObject); + } + return .js_undefined; +} + pub const getCwd = JSC.host_fn.wrap1(getCwd_); fn getCwd_(globalObject: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { var buf: bun.PathBuffer = undefined; diff --git a/src/js/node/child_process.ts b/src/js/node/child_process.ts index 7ea8e20ec0..458e3dae39 100644 --- a/src/js/node/child_process.ts +++ b/src/js/node/child_process.ts @@ -30,6 +30,8 @@ const ArrayPrototypeFilter = Array.prototype.filter; const ArrayPrototypeSort = Array.prototype.sort; const StringPrototypeToUpperCase = String.prototype.toUpperCase; const ArrayPrototypePush = Array.prototype.push; +const ArrayPrototypeLastIndexOf = Array.prototype.lastIndexOf; +const ArrayPrototypeSplice = Array.prototype.splice; var ArrayBufferIsView = ArrayBuffer.isView; @@ -735,19 +737,19 @@ function fork(modulePath, args = [], options) { validateArgumentNullCheck(options.execPath, "options.execPath"); // Prepare arguments for fork: - // execArgv = options.execArgv || process.execArgv; - // validateArgumentsNullCheck(execArgv, "options.execArgv"); + let execArgv = options.execArgv || process.execArgv; + validateArgumentsNullCheck(execArgv, "options.execArgv"); - // if (execArgv === process.execArgv && process._eval != null) { - // const index = ArrayPrototypeLastIndexOf.$call(execArgv, process._eval); - // if (index > 0) { - // // Remove the -e switch to avoid fork bombing ourselves. - // execArgv = ArrayPrototypeSlice.$call(execArgv); - // ArrayPrototypeSplice.$call(execArgv, index - 1, 2); - // } - // } + if (execArgv === process.execArgv && process._eval != null) { + const index = ArrayPrototypeLastIndexOf.$call(execArgv, process._eval); + if (index > 0) { + // Remove the -e switch to avoid fork bombing ourselves. + execArgv = ArrayPrototypeSlice.$call(execArgv); + ArrayPrototypeSplice.$call(execArgv, index - 1, 2); + } + } - args = [/*...execArgv,*/ modulePath, ...args]; + args = [...execArgv, modulePath, ...args]; if (typeof options.stdio === "string") { options.stdio = stdioStringToArray(options.stdio, "ipc"); diff --git a/test/cli/run/run-eval.test.ts b/test/cli/run/run-eval.test.ts index 6df01acc37..90219278ca 100644 --- a/test/cli/run/run-eval.test.ts +++ b/test/cli/run/run-eval.test.ts @@ -64,6 +64,15 @@ for (const flag of ["-e", "--print"]) { testProcessArgv(["--", "abc", "def"], [exe, "abc", "def"]); // testProcessArgv(["--", "abc", "--", "def"], [exe, "abc", "--", "def"]); }); + + test("process._eval", async () => { + const code = flag === "--print" ? "process._eval" : "console.log(process._eval)"; + const { stdout } = Bun.spawnSync({ + cmd: [bunExe(), flag, code], + env: bunEnv, + }); + expect(stdout.toString("utf8")).toEqual(code + "\n"); + }); }); } @@ -140,6 +149,18 @@ function group(run: (code: string) => SyncSubprocess<"pipe", "inherit">) { const exe = isWindows ? bunExe().replaceAll("/", "\\") : bunExe(); expect(JSON.parse(stdout.toString("utf8"))).toEqual([exe, "-"]); }); + + test("process._eval", async () => { + const code = "console.log(process._eval)"; + const { stdout } = run(code); + + // the file piping one on windows can include extra carriage returns + if (isWindows) { + expect(stdout.toString("utf8")).toInclude(code); + } else { + expect(stdout.toString("utf8")).toEqual(code + "\n"); + } + }); } describe("bun run - < file-path.js", () => { @@ -196,3 +217,18 @@ describe("echo | bun run -", () => { group(run); }); + +test("process._eval (undefined for normal run)", async () => { + const cwd = tmpdirSync(); + const file = join(cwd, "test.js"); + writeFileSync(file, "console.log(typeof process._eval)"); + + const { stdout } = Bun.spawnSync({ + cmd: [bunExe(), "run", file], + cwd: cwd, + env: bunEnv, + }); + expect(stdout.toString("utf8")).toEqual("undefined\n"); + + rmSync(cwd, { recursive: true, force: true }); +}); diff --git a/test/js/node/test/parallel/test-child-process-fork-exec-argv.js b/test/js/node/test/parallel/test-child-process-fork-exec-argv.js new file mode 100644 index 0000000000..f1e3bbbc58 --- /dev/null +++ b/test/js/node/test/parallel/test-child-process-fork-exec-argv.js @@ -0,0 +1,49 @@ +// 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 child_process = require('child_process'); +const spawn = child_process.spawn; +const fork = child_process.fork; + +if (process.argv[2] === 'fork') { + process.stdout.write(JSON.stringify(process.execArgv), function() { + process.exit(); + }); +} else if (process.argv[2] === 'child') { + fork(__filename, ['fork']); +} else { + const execArgv = ['--stack-size=256']; + const args = [__filename, 'child', 'arg0']; + + const child = spawn(process.execPath, execArgv.concat(args)); + let out = ''; + + child.stdout.on('data', function(chunk) { + out += chunk; + }); + + child.on('exit', common.mustCall(function() { + assert.deepStrictEqual(JSON.parse(out), execArgv); + })); +} diff --git a/test/no-validate-exceptions.txt b/test/no-validate-exceptions.txt index a97a604e7f..b313ae40dc 100644 --- a/test/no-validate-exceptions.txt +++ b/test/no-validate-exceptions.txt @@ -151,14 +151,12 @@ test/js/bun/s3/s3-insecure.test.ts test/js/bun/s3/s3-list-objects.test.ts test/js/bun/s3/s3-storage-class.test.ts test/js/bun/s3/s3.test.ts -test/js/bun/shell/yield.test.ts -test/js/bun/shell/file-io.test.ts -test/js/bun/shell/commands/echo.test.ts test/js/bun/shell/bunshell-default.test.ts test/js/bun/shell/bunshell-file.test.ts test/js/bun/shell/bunshell-instance.test.ts test/js/bun/shell/commands/basename.test.ts test/js/bun/shell/commands/dirname.test.ts +test/js/bun/shell/commands/echo.test.ts test/js/bun/shell/commands/exit.test.ts test/js/bun/shell/commands/false.test.ts test/js/bun/shell/commands/mv.test.ts @@ -169,6 +167,7 @@ test/js/bun/shell/commands/which.test.ts test/js/bun/shell/commands/yes.test.ts test/js/bun/shell/env.positionals.test.ts test/js/bun/shell/exec.test.ts +test/js/bun/shell/file-io.test.ts test/js/bun/shell/lazy.test.ts test/js/bun/shell/leak.test.ts test/js/bun/shell/lex.test.ts @@ -176,6 +175,7 @@ test/js/bun/shell/shell-hang.test.ts test/js/bun/shell/shell-load.test.ts test/js/bun/shell/shelloutput.test.ts test/js/bun/shell/throw.test.ts +test/js/bun/shell/yield.test.ts test/js/bun/spawn/bun-ipc-inherit.test.ts test/js/bun/spawn/job-object-bug.test.ts test/js/bun/spawn/spawn_waiter_thread.test.ts @@ -477,6 +477,7 @@ test/js/node/test/parallel/test-child-process-fork-args.js test/js/node/test/parallel/test-child-process-fork-close.js test/js/node/test/parallel/test-child-process-fork-closed-channel-segfault.js test/js/node/test/parallel/test-child-process-fork-detached.js +test/js/node/test/parallel/test-child-process-fork-exec-argv.js test/js/node/test/parallel/test-child-process-fork-exec-path.js test/js/node/test/parallel/test-child-process-fork-no-shell.js test/js/node/test/parallel/test-child-process-fork-ref.js