From b432006e439fcde9f8748fd369ad0e33a22bf347 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 12 Sep 2023 06:34:20 -0700 Subject: Clean up some edgecases with posix_spawn usage (#5079) * Check that the pid matches * Fixup EINTR check * Remove extra slashes * fixup * fixup * != 0 --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> --- src/bun.js/api/bun/subprocess.zig | 76 +++++++++++++++++++++++++++++---------- src/install/install.zig | 10 +++++- 2 files changed, 66 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 50bd846ac..5695c15ad 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -1462,25 +1462,61 @@ pub const Subprocess = struct { const kernel = @import("../../../analytics.zig").GenerateHeader.GeneratePlatform.kernelVersion(); // pidfd_nonblock only supported in 5.10+ - const pidfd_flags: u32 = if (!is_sync and kernel.orderWithoutTag(.{ .major = 5, .minor = 10, .patch = 0 }).compare(.gte)) + var pidfd_flags: u32 = if (!is_sync and kernel.orderWithoutTag(.{ .major = 5, .minor = 10, .patch = 0 }).compare(.gte)) std.os.O.NONBLOCK else 0; - const fd = std.os.linux.pidfd_open( - pid, + var rc = std.os.linux.pidfd_open( + @intCast(pid), pidfd_flags, ); - switch (std.os.linux.getErrno(fd)) { - .SUCCESS => break :brk @as(std.os.fd_t, @intCast(fd)), - else => |err| { - globalThis.throwValue(bun.sys.Error.fromCode(err, .open).toJSC(globalThis)); - var status: u32 = 0; - // ensure we don't leak the child process on error - _ = std.os.linux.waitpid(pid, &status, 0); - return .zero; - }, + while (true) { + switch (std.os.linux.getErrno(rc)) { + .SUCCESS => break :brk @as(std.os.fd_t, @intCast(rc)), + .INTR => { + rc = std.os.linux.pidfd_open( + @intCast(pid), + pidfd_flags, + ); + continue; + }, + else => |err| { + if (err == .INVAL) { + if (pidfd_flags != 0) { + rc = std.os.linux.pidfd_open( + @intCast(pid), + 0, + ); + pidfd_flags = 0; + continue; + } + } + + const error_instance = brk2: { + if (err == .NOSYS) { + break :brk2 globalThis.createErrorInstance( + \\"pidfd_open(2)" system call is not supported by your Linux kernel + \\To fix this error, either: + \\- Upgrade your Linux kernel to a newer version (current: {}) + \\- Ensure the seccomp filter allows "pidfd_open" + , + .{ + kernel.fmt(""), + }, + ); + } + + break :brk2 bun.sys.Error.fromCode(err, .open).toJSC(globalThis); + }; + globalThis.throwValue(error_instance); + var status: u32 = 0; + // ensure we don't leak the child process on error + _ = std.os.linux.waitpid(pid, &status, 0); + return .zero; + }, + } } }; @@ -1682,14 +1718,16 @@ pub const Subprocess = struct { this.waitpid_err = err; }, .result => |result| { - if (std.os.W.IFEXITED(result.status)) { - this.exit_code = @as(u8, @truncate(std.os.W.EXITSTATUS(result.status))); - } + if (result.pid != 0) { + if (std.os.W.IFEXITED(result.status)) { + this.exit_code = @as(u8, @truncate(std.os.W.EXITSTATUS(result.status))); + } - if (std.os.W.IFSIGNALED(result.status)) { - this.signal_code = @as(SignalCode, @enumFromInt(@as(u8, @truncate(std.os.W.TERMSIG(result.status))))); - } else if (std.os.W.IFSTOPPED(result.status)) { - this.signal_code = @as(SignalCode, @enumFromInt(@as(u8, @truncate(std.os.W.STOPSIG(result.status))))); + if (std.os.W.IFSIGNALED(result.status)) { + this.signal_code = @as(SignalCode, @enumFromInt(@as(u8, @truncate(std.os.W.TERMSIG(result.status))))); + } else if (std.os.W.IFSTOPPED(result.status)) { + this.signal_code = @as(SignalCode, @enumFromInt(@as(u8, @truncate(std.os.W.STOPSIG(result.status))))); + } } if (!this.hasExited()) { diff --git a/src/install/install.zig b/src/install/install.zig index d7113cfe9..bcf33cb53 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1250,7 +1250,15 @@ const PackageInstall = struct { std.os.mkdirat(destination_dir_.dir.fd, entry.path, 0o755) catch {}; }, .file => { - try std.os.linkat(entry.dir.dir.fd, entry.basename, destination_dir_.dir.fd, entry.path, 0); + std.os.linkat(entry.dir.dir.fd, entry.basename, destination_dir_.dir.fd, entry.path, 0) catch |err| { + if (err != error.PathAlreadyExists) { + return err; + } + + std.os.unlinkat(destination_dir_.dir.fd, entry.path, 0) catch {}; + try std.os.linkat(entry.dir.dir.fd, entry.basename, destination_dir_.dir.fd, entry.path, 0); + }; + real_file_count += 1; }, else => {}, -- cgit v1.2.3