From 1f7d64cc054238fc3320c465be3877a93ffcdc52 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Tue, 4 Mar 2025 13:21:39 -0800 Subject: [PATCH] fix(shell): remove unecessary allocations when printing errors --- src/shell/interpreter.zig | 17 ++++++----------- src/shell/shell.zig | 31 ++++++++----------------------- 2 files changed, 14 insertions(+), 34 deletions(-) diff --git a/src/shell/interpreter.zig b/src/shell/interpreter.zig index 8fb1d689047e40..387e2f091a6a5e 100644 --- a/src/shell/interpreter.zig +++ b/src/shell/interpreter.zig @@ -3671,8 +3671,7 @@ pub const Interpreter = struct { const err = this.state.expanding_redirect.expansion.state.err; defer err.deinit(bun.default_allocator); this.state.expanding_redirect.expansion.deinit(); - const buf = err.fmt(); - this.writeFailingError("{s}", .{buf}); + this.writeFailingError("{}\n", .{err}); return; } this.next(); @@ -4089,8 +4088,7 @@ pub const Interpreter = struct { const err = this.state.expanding_args.expansion.state.err; defer err.deinit(bun.default_allocator); this.state.expanding_args.expansion.deinit(); - const buf = err.fmt(); - this.writeFailingError("{s}", .{buf}); + this.writeFailingError("{}\n", .{err}); return; } child.deinit(); @@ -4691,8 +4689,7 @@ pub const Interpreter = struct { const err = this.state.expanding_assigns.state.err; defer err.deinit(bun.default_allocator); this.state.expanding_assigns.deinit(); - const buf = err.fmt(); - this.writeFailingError("{s}", .{buf}); + this.writeFailingError("{}\n", .{err}); return; } @@ -4715,8 +4712,7 @@ pub const Interpreter = struct { else => @panic("Invalid state"), }; defer err.deinit(bun.default_allocator); - const buf = err.fmt(); - this.writeFailingError("{s}", .{buf}); + this.writeFailingError("{}\n", .{err}); return; } // Handling this case from the shell spec: @@ -4936,12 +4932,11 @@ pub const Interpreter = struct { .buffered_closed = buffered_closed, } }; const subproc = switch (Subprocess.spawnAsync(this.base.eventLoop(), &shellio, spawn_args, &this.exec.subproc.child)) { + // FIXME: There's a race condition where this could change variants before spawnAsync returns. .result => this.exec.subproc.child, .err => |*e| { this.exec = .none; - const msg = e.fmt(); - defer bun.default_allocator.free(msg); - this.writeFailingError("{s}", .{msg}); + this.writeFailingError("{}\n", .{e}); return; }, }; diff --git a/src/shell/shell.zig b/src/shell/shell.zig index 69c36714b2a0b4..11db1ee23108e0 100644 --- a/src/shell/shell.zig +++ b/src/shell/shell.zig @@ -62,25 +62,13 @@ pub const ShellErr = union(enum) { }; } - pub fn fmt(this: @This()) []const u8 { - switch (this) { - .sys => { - const err = this.sys; - const str = std.fmt.allocPrint(bun.default_allocator, "bun: {s}: {}\n", .{ err.message, err.path }) catch bun.outOfMemory(); - return str; - }, - .custom => { - return std.fmt.allocPrint(bun.default_allocator, "bun: {s}\n", .{this.custom}) catch bun.outOfMemory(); - }, - .invalid_arguments => { - const str = std.fmt.allocPrint(bun.default_allocator, "bun: invalid arguments: {s}\n", .{this.invalid_arguments.val}) catch bun.outOfMemory(); - return str; - }, - .todo => { - const str = std.fmt.allocPrint(bun.default_allocator, "bun: TODO: {s}\n", .{this.invalid_arguments.val}) catch bun.outOfMemory(); - return str; - }, - } + pub fn format(this: *const ShellErr, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + return switch (this.*) { + .sys => |e| writer.print("bun: {s}: {}", .{ e.message, e.path }), + .custom => |msg| writer.print("bun: {s}", .{msg}), + .invalid_arguments => |args| writer.print("bun: invalid arguments: {s}", .{args.val}), + .todo => |msg| writer.print("bun: TODO: {s}", .{msg}), + }; } pub fn throwJS(this: *const @This(), globalThis: *JSC.JSGlobalObject) bun.JSError { @@ -111,21 +99,18 @@ pub const ShellErr = union(enum) { switch (this) { .sys => |err| { bun.Output.prettyErrorln("error: Failed due to error: bunsh: {s}: {}", .{ err.message, err.path }); - bun.Global.exit(1); }, .custom => |custom| { bun.Output.prettyErrorln("error: Failed due to error: {s}", .{custom}); - bun.Global.exit(1); }, .invalid_arguments => |invalid_arguments| { bun.Output.prettyErrorln("error: Failed due to error: bunsh: invalid arguments: {s}", .{invalid_arguments.val}); - bun.Global.exit(1); }, .todo => |todo| { bun.Output.prettyErrorln("error: Failed due to error: TODO: {s}", .{todo}); - bun.Global.exit(1); }, } + bun.Global.exit(1); } pub fn deinit(this: @This(), allocator: Allocator) void {