### What does this PR do?
`CompileResult` error message memory was not managed correctly.

Fixes #23470

### How did you verify your code works?
Manually
This commit is contained in:
Dylan Conway
2025-10-11 08:23:25 -07:00
committed by GitHub
parent f673ed8821
commit 85a2ebb717
4 changed files with 71 additions and 40 deletions

View File

@@ -525,15 +525,48 @@ pub const StandaloneModuleGraph = struct {
pub const CompileResult = union(enum) {
success: void,
error_message: []const u8,
pub fn fail(msg: []const u8) CompileResult {
return .{ .error_message = msg };
err: Error,
const Error = union(enum) {
message: []const u8,
reason: Reason,
pub const Reason = enum {
no_entry_point,
no_output_files,
pub fn message(this: Reason) []const u8 {
return switch (this) {
.no_entry_point => "No entry point found for compilation",
.no_output_files => "No output files to bundle",
};
}
};
pub fn slice(this: *const Error) []const u8 {
return switch (this.*) {
.message => this.message,
.reason => this.reason.message(),
};
}
};
pub fn fail(reason: Error.Reason) CompileResult {
return .{ .err = .{ .reason = reason } };
}
pub fn failFmt(comptime fmt: []const u8, args: anytype) CompileResult {
return .{ .err = .{ .message = bun.handleOom(std.fmt.allocPrint(bun.default_allocator, fmt, args)) } };
}
pub fn deinit(this: *const @This()) void {
if (this.* == .error_message) {
bun.default_allocator.free(this.error_message);
switch (this.*) {
.success => {},
.err => switch (this.err) {
.message => bun.default_allocator.free(this.err.message),
.reason => {},
},
}
}
};
@@ -951,9 +984,9 @@ pub const StandaloneModuleGraph = struct {
self_exe_path: ?[]const u8,
) !CompileResult {
const bytes = toBytes(allocator, module_prefix, output_files, output_format, compile_exec_argv) catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "failed to generate module graph bytes: {s}", .{@errorName(err)}) catch "failed to generate module graph bytes");
return CompileResult.failFmt("failed to generate module graph bytes: {s}", .{@errorName(err)});
};
if (bytes.len == 0) return CompileResult.fail("no output files to bundle");
if (bytes.len == 0) return CompileResult.fail(.no_output_files);
defer allocator.free(bytes);
var free_self_exe = false;
@@ -962,28 +995,26 @@ pub const StandaloneModuleGraph = struct {
break :brk bun.handleOom(allocator.dupeZ(u8, path));
} else if (target.isDefault())
bun.selfExePath() catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "failed to get self executable path: {s}", .{@errorName(err)}) catch "failed to get self executable path");
return CompileResult.failFmt("failed to get self executable path: {s}", .{@errorName(err)});
}
else blk: {
var exe_path_buf: bun.PathBuffer = undefined;
var version_str_buf: [1024]u8 = undefined;
const version_str = std.fmt.bufPrintZ(&version_str_buf, "{}", .{target}) catch {
return CompileResult.fail("failed to format target version string");
};
const version_str = bun.handleOom(std.fmt.allocPrintZ(allocator, "{}", .{target}));
defer allocator.free(version_str);
var needs_download: bool = true;
const dest_z = target.exePath(&exe_path_buf, version_str, env, &needs_download);
if (needs_download) {
target.downloadToPath(env, allocator, dest_z) catch |err| {
const msg = switch (err) {
error.TargetNotFound => std.fmt.allocPrint(allocator, "Target platform '{}' is not available for download. Check if this version of Bun supports this target.", .{target}) catch "Target platform not available for download",
error.NetworkError => std.fmt.allocPrint(allocator, "Network error downloading executable for '{}'. Check your internet connection and proxy settings.", .{target}) catch "Network error downloading executable",
error.InvalidResponse => std.fmt.allocPrint(allocator, "Downloaded file for '{}' appears to be corrupted. Please try again.", .{target}) catch "Downloaded file is corrupted",
error.ExtractionFailed => std.fmt.allocPrint(allocator, "Failed to extract executable for '{}'. The download may be incomplete.", .{target}) catch "Failed to extract downloaded executable",
error.UnsupportedTarget => std.fmt.allocPrint(allocator, "Target '{}' is not supported", .{target}) catch "Unsupported target",
else => std.fmt.allocPrint(allocator, "Failed to download '{}': {s}", .{ target, @errorName(err) }) catch "Download failed",
return switch (err) {
error.TargetNotFound => CompileResult.failFmt("Target platform '{}' is not available for download. Check if this version of Bun supports this target.", .{target}),
error.NetworkError => CompileResult.failFmt("Network error downloading executable for '{}'. Check your internet connection and proxy settings.", .{target}),
error.InvalidResponse => CompileResult.failFmt("Downloaded file for '{}' appears to be corrupted. Please try again.", .{target}),
error.ExtractionFailed => CompileResult.failFmt("Failed to extract executable for '{}'. The download may be incomplete.", .{target}),
error.UnsupportedTarget => CompileResult.failFmt("Target '{}' is not supported", .{target}),
else => CompileResult.failFmt("Failed to download '{}': {s}", .{ target, @errorName(err) }),
};
return CompileResult.fail(msg);
};
}
@@ -1013,7 +1044,7 @@ pub const StandaloneModuleGraph = struct {
// Get the current path of the temp file
var temp_buf: bun.PathBuffer = undefined;
const temp_path = bun.getFdPath(fd, &temp_buf) catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "Failed to get temp file path: {s}", .{@errorName(err)}) catch "Failed to get temp file path");
return CompileResult.failFmt("Failed to get temp file path: {s}", .{@errorName(err)});
};
// Build the absolute destination path
@@ -1021,7 +1052,7 @@ pub const StandaloneModuleGraph = struct {
// Get the current working directory and join with outfile
var cwd_buf: bun.PathBuffer = undefined;
const cwd_path = bun.getcwd(&cwd_buf) catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "Failed to get current directory: {s}", .{@errorName(err)}) catch "Failed to get current directory");
return CompileResult.failFmt("Failed to get current directory: {s}", .{@errorName(err)});
};
const dest_path = if (std.fs.path.isAbsolute(outfile))
outfile
@@ -1049,12 +1080,12 @@ pub const StandaloneModuleGraph = struct {
const err = bun.windows.Win32Error.get();
if (err.toSystemErrno()) |sys_err| {
if (sys_err == .EISDIR) {
return CompileResult.fail(std.fmt.allocPrint(allocator, "{s} is a directory. Please choose a different --outfile or delete the directory", .{outfile}) catch "outfile is a directory");
return CompileResult.failFmt("{s} is a directory. Please choose a different --outfile or delete the directory", .{outfile});
} else {
return CompileResult.fail(std.fmt.allocPrint(allocator, "failed to move executable to {s}: {s}", .{ dest_path, @tagName(sys_err) }) catch "failed to move executable");
return CompileResult.failFmt("failed to move executable to {s}: {s}", .{ dest_path, @tagName(sys_err) });
}
} else {
return CompileResult.fail(std.fmt.allocPrint(allocator, "failed to move executable to {s}", .{dest_path}) catch "failed to move executable");
return CompileResult.failFmt("failed to move executable to {s}", .{dest_path});
}
}
@@ -1076,7 +1107,7 @@ pub const StandaloneModuleGraph = struct {
windows_options.description,
windows_options.copyright,
) catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "Failed to set Windows metadata: {s}", .{@errorName(err)}) catch "Failed to set Windows metadata");
return CompileResult.failFmt("Failed to set Windows metadata: {s}", .{@errorName(err)});
};
}
return .success;
@@ -1084,14 +1115,14 @@ pub const StandaloneModuleGraph = struct {
var buf: bun.PathBuffer = undefined;
const temp_location = bun.getFdPath(fd, &buf) catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "failed to get path for fd: {s}", .{@errorName(err)}) catch "failed to get path for file descriptor");
return CompileResult.failFmt("failed to get path for fd: {s}", .{@errorName(err)});
};
const temp_posix = std.posix.toPosixPath(temp_location) catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "path too long: {s}", .{@errorName(err)}) catch "path too long");
return CompileResult.failFmt("path too long: {s}", .{@errorName(err)});
};
const outfile_basename = std.fs.path.basename(outfile);
const outfile_posix = std.posix.toPosixPath(outfile_basename) catch |err| {
return CompileResult.fail(std.fmt.allocPrint(allocator, "outfile name too long: {s}", .{@errorName(err)}) catch "outfile name too long");
return CompileResult.failFmt("outfile name too long: {s}", .{@errorName(err)});
};
bun.sys.moveFileZWithHandle(
@@ -1107,9 +1138,9 @@ pub const StandaloneModuleGraph = struct {
_ = Syscall.unlink(&temp_posix);
if (err == error.IsDir or err == error.EISDIR) {
return CompileResult.fail(std.fmt.allocPrint(allocator, "{s} is a directory. Please choose a different --outfile or delete the directory", .{outfile}) catch "outfile is a directory");
return CompileResult.failFmt("{s} is a directory. Please choose a different --outfile or delete the directory", .{outfile});
} else {
return CompileResult.fail(std.fmt.allocPrint(allocator, "failed to rename {s} to {s}: {s}", .{ temp_location, outfile, @errorName(err) }) catch "failed to rename file");
return CompileResult.failFmt("failed to rename {s} to {s}: {s}", .{ temp_location, outfile, @errorName(err) });
}
};