Skip to content

eliminate posix_spawnp from the standard library #14866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,6 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/io_uring.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/x86_64.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/posix_spawn.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows/ntstatus.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows/win32error.zig"
Expand Down
2 changes: 0 additions & 2 deletions lib/std/Build/CompileStep.zig
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,6 @@ pub fn runPkgConfig(self: *CompileStep, lib_name: []const u8) ![]const []const u
error.ExecNotSupported => return error.PkgConfigFailed,
error.ExitCodeFailure => return error.PkgConfigFailed,
error.FileNotFound => return error.PkgConfigNotInstalled,
error.ChildExecFailed => return error.PkgConfigFailed,
else => return err,
};

Expand Down Expand Up @@ -2042,7 +2041,6 @@ fn getPkgConfigList(self: *std.Build) ![]const PkgConfigPkg {
error.FileNotFound => error.PkgConfigNotInstalled,
error.InvalidName => error.PkgConfigNotInstalled,
error.PkgConfigInvalidOutput => error.PkgConfigInvalidOutput,
error.ChildExecFailed => error.PkgConfigFailed,
else => return err,
};
self.pkg_config_pkg_list = result;
Expand Down
127 changes: 2 additions & 125 deletions lib/std/child_process.zig
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ pub const ChildProcess = struct {
os.SetIdError ||
os.ChangeCurDirError ||
windows.CreateProcessError ||
windows.WaitForSingleObjectError ||
os.posix_spawn.Error;
windows.WaitForSingleObjectError;

pub const Term = union(enum) {
Exited: u8,
Expand Down Expand Up @@ -143,10 +142,6 @@ pub const ChildProcess = struct {
@compileError("the target operating system cannot spawn processes");
}

if (comptime builtin.target.isDarwin()) {
return self.spawnMacos();
}

if (builtin.os.tag == .windows) {
return self.spawnWindows();
} else {
Expand Down Expand Up @@ -337,10 +332,7 @@ pub const ChildProcess = struct {
}

fn waitUnwrapped(self: *ChildProcess) !void {
const res: os.WaitPidResult = if (comptime builtin.target.isDarwin())
try os.posix_spawn.waitpid(self.id, 0)
else
os.waitpid(self.id, 0);
const res: os.WaitPidResult = os.waitpid(self.id, 0);
const status = res.status;
self.cleanupStreams();
self.handleWaitResult(status);
Expand Down Expand Up @@ -416,121 +408,6 @@ pub const ChildProcess = struct {
Term{ .Unknown = status };
}

fn spawnMacos(self: *ChildProcess) SpawnError!void {
const pipe_flags = if (io.is_async) os.O.NONBLOCK else 0;
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
errdefer if (self.stdin_behavior == StdIo.Pipe) destroyPipe(stdin_pipe);

const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
errdefer if (self.stdout_behavior == StdIo.Pipe) destroyPipe(stdout_pipe);

const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
errdefer if (self.stderr_behavior == StdIo.Pipe) destroyPipe(stderr_pipe);

const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
const dev_null_fd = if (any_ignore)
os.openZ("/dev/null", os.O.RDWR, 0) catch |err| switch (err) {
error.PathAlreadyExists => unreachable,
error.NoSpaceLeft => unreachable,
error.FileTooBig => unreachable,
error.DeviceBusy => unreachable,
error.FileLocksNotSupported => unreachable,
error.BadPathName => unreachable, // Windows-only
error.InvalidHandle => unreachable, // WASI-only
error.WouldBlock => unreachable,
else => |e| return e,
}
else
undefined;
defer if (any_ignore) os.close(dev_null_fd);

var attr = try os.posix_spawn.Attr.init();
defer attr.deinit();
var flags: u16 = os.darwin.POSIX_SPAWN_SETSIGDEF | os.darwin.POSIX_SPAWN_SETSIGMASK;
if (self.disable_aslr) {
flags |= os.darwin._POSIX_SPAWN_DISABLE_ASLR;
}
if (self.start_suspended) {
flags |= os.darwin.POSIX_SPAWN_START_SUSPENDED;
}
try attr.set(flags);

var actions = try os.posix_spawn.Actions.init();
defer actions.deinit();

try setUpChildIoPosixSpawn(self.stdin_behavior, &actions, stdin_pipe, os.STDIN_FILENO, dev_null_fd);
try setUpChildIoPosixSpawn(self.stdout_behavior, &actions, stdout_pipe, os.STDOUT_FILENO, dev_null_fd);
try setUpChildIoPosixSpawn(self.stderr_behavior, &actions, stderr_pipe, os.STDERR_FILENO, dev_null_fd);

if (self.cwd_dir) |cwd| {
try actions.fchdir(cwd.fd);
} else if (self.cwd) |cwd| {
try actions.chdir(cwd);
}

var arena_allocator = std.heap.ArenaAllocator.init(self.allocator);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();

const argv_buf = try arena.allocSentinel(?[*:0]u8, self.argv.len, null);
for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;

const envp = if (self.env_map) |env_map| m: {
const envp_buf = try createNullDelimitedEnvMap(arena, env_map);
break :m envp_buf.ptr;
} else std.c.environ;

const pid = try os.posix_spawn.spawnp(self.argv[0], actions, attr, argv_buf, envp);

if (self.stdin_behavior == StdIo.Pipe) {
self.stdin = File{ .handle = stdin_pipe[1] };
} else {
self.stdin = null;
}
if (self.stdout_behavior == StdIo.Pipe) {
self.stdout = File{ .handle = stdout_pipe[0] };
} else {
self.stdout = null;
}
if (self.stderr_behavior == StdIo.Pipe) {
self.stderr = File{ .handle = stderr_pipe[0] };
} else {
self.stderr = null;
}

self.id = pid;
self.term = null;

if (self.stdin_behavior == StdIo.Pipe) {
os.close(stdin_pipe[0]);
}
if (self.stdout_behavior == StdIo.Pipe) {
os.close(stdout_pipe[1]);
}
if (self.stderr_behavior == StdIo.Pipe) {
os.close(stderr_pipe[1]);
}
}

fn setUpChildIoPosixSpawn(
stdio: StdIo,
actions: *os.posix_spawn.Actions,
pipe_fd: [2]i32,
std_fileno: i32,
dev_null_fd: i32,
) !void {
switch (stdio) {
.Pipe => {
const idx: usize = if (std_fileno == 0) 0 else 1;
try actions.dup2(pipe_fd[idx], std_fileno);
try actions.close(pipe_fd[1 - idx]);
},
.Close => try actions.close(std_fileno),
.Inherit => {},
.Ignore => try actions.dup2(dev_null_fd, std_fileno),
}
}

fn spawnPosix(self: *ChildProcess) SpawnError!void {
const pipe_flags = if (io.is_async) os.O.NONBLOCK else 0;
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
Expand Down
5 changes: 1 addition & 4 deletions lib/std/os.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ pub const plan9 = @import("os/plan9.zig");
pub const uefi = @import("os/uefi.zig");
pub const wasi = @import("os/wasi.zig");
pub const windows = @import("os/windows.zig");
pub const posix_spawn = @import("os/posix_spawn.zig");
pub const ptrace = @import("os/ptrace.zig");

comptime {
Expand All @@ -56,7 +55,6 @@ test {
}
_ = wasi;
_ = windows;
_ = posix_spawn;

_ = @import("os/test.zig");
}
Expand Down Expand Up @@ -3998,8 +3996,7 @@ pub const WaitPidResult = struct {
};

/// Use this version of the `waitpid` wrapper if you spawned your child process using explicit
/// `fork` and `execve` method. If you spawned your child process using `posix_spawn` method,
/// use `std.os.posix_spawn.waitpid` instead.
/// `fork` and `execve` method.
pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult {
const Status = if (builtin.link_libc) c_int else u32;
var status: Status = undefined;
Expand Down
Loading