mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 11:29:02 +00:00
## What does this PR do? Fixes https://github.com/oven-sh/bun/issues/22650 Fixes https://github.com/oven-sh/bun/issues/22615 Fixes https://github.com/oven-sh/bun/issues/22603 Fixes https://github.com/oven-sh/bun/issues/22602 Fixes a crash that occurred when running shell commands through `bun run` (package.json scripts) on Windows that use the `&&` operator followed by an external command. ### The Problem The minimal reproduction was: ```bash bun exec 'echo && node --version' ``` This would crash with: `panic(main thread): attempt to use null value` ### Root Causes Two issues were causing the crash: 1. **Missing top_level_dir**: When `runPackageScriptForeground` creates a MiniEventLoop for running package scripts, it wasn't setting the `top_level_dir` field. This caused a null pointer dereference when the shell tried to access it. 2. **MovableIfWindowsFd handling**: After PR #21800 introduced `MovableIfWindowsFd` to handle file descriptor ownership on Windows, the `IOWriter.fd` could be moved to libuv, leaving it null. When the shell tried to spawn an external command after a `&&` operator, it would crash trying to access this null fd. ### The Fix 1. Set `mini.top_level_dir = cwd` after initializing the MiniEventLoop in `run_command.zig` 2. In `IO.zig`, when the fd has been moved to libuv (is null), use `.inherit` for stdio instead of trying to pass the null fd ### How did you verify your code works? - Added a regression test that reproduces the issue - Verified the test fails without the fix and passes with it - Tested the minimal reproduction command directly - The fix correctly allows both commands in the `&&` chain to execute ```bash # Before fix: crashes > bun exec 'echo test && node --version' panic(main thread): attempt to use null value # After fix: works correctly > bun exec 'echo test && node --version' test v22.4.1 ``` <sub> also probably fixes #22615 and fixes #22603 and fixes #22602 </sub> --------- Co-authored-by: Zack Radisic <zack@theradisic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
47 lines
1.7 KiB
Zig
47 lines
1.7 KiB
Zig
pub const ExecCommand = struct {
|
|
pub fn exec(ctx: Command.Context) !void {
|
|
const script = ctx.positionals[1];
|
|
// this is a hack: make dummy bundler so we can use its `.runEnvLoader()` function to populate environment variables probably should split out the functionality
|
|
var bundle = try bun.Transpiler.init(
|
|
ctx.allocator,
|
|
ctx.log,
|
|
try @import("../bun.js/config.zig").configureTransformOptionsForBunVM(ctx.allocator, ctx.args),
|
|
null,
|
|
);
|
|
try bundle.runEnvLoader(false);
|
|
var buf: bun.PathBuffer = undefined;
|
|
const cwd = switch (bun.sys.getcwd(&buf)) {
|
|
.result => |p| p,
|
|
.err => |e| {
|
|
Output.err(e, "failed to run script <b>{s}<r>", .{script});
|
|
Global.exit(1);
|
|
},
|
|
};
|
|
const mini = bun.jsc.MiniEventLoop.initGlobal(bundle.env, cwd);
|
|
const parts: []const []const u8 = &[_][]const u8{
|
|
cwd,
|
|
"[eval]",
|
|
};
|
|
const script_path = bun.path.join(parts, .auto);
|
|
|
|
const code = bun.shell.Interpreter.initAndRunFromSource(ctx, mini, script_path, script, null) catch |err| {
|
|
Output.err(err, "failed to run script <b>{s}<r>", .{script_path});
|
|
Global.exit(1);
|
|
};
|
|
|
|
// if (code > 0) {
|
|
// if (code != 2 and !silent) {
|
|
// Output.prettyErrorln("<r><red>error<r><d>:<r> script <b>\"{s}\"<r> exited with code {d}<r>", .{ name, code });
|
|
// Output.flush();
|
|
// }
|
|
|
|
Global.exit(code);
|
|
// }
|
|
}
|
|
};
|
|
|
|
const bun = @import("bun");
|
|
const Global = bun.Global;
|
|
const Output = bun.Output;
|
|
const Command = bun.cli.Command;
|