Skip to content

Commit

Permalink
Merge pull request #2 from coolreader18/runmake-fd3
Browse files Browse the repository at this point in the history
Add fd3 support to runmake
  • Loading branch information
Oneirical authored Sep 14, 2024
2 parents 97091f2 + 0eb50a0 commit 77c21c5
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 12 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3149,6 +3149,7 @@ dependencies = [
"bstr",
"build_helper",
"gimli 0.31.0",
"libc",
"object 0.36.2",
"regex",
"similar",
Expand Down
1 change: 1 addition & 0 deletions src/tools/run-make-support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ similar = "2.5.0"
wasmparser = { version = "0.214", default-features = false, features = ["std"] }
regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
gimli = "0.31.0"
libc = "0.2"
build_helper = { path = "../build_helper" }
40 changes: 40 additions & 0 deletions src/tools/run-make-support/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,46 @@ impl Command {
self
}

/// Set an auxiliary stream passed to the process, besides the stdio streams.
///
/// Use with caution - ideally, only set one aux fd; if there are multiple,
/// their old `fd` may overlap with another's `newfd`, and thus will break.
/// If you need more than 1 auxiliary file descriptor, rewrite this function
/// to be able to support that.
#[cfg(unix)]
pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
&mut self,
newfd: std::os::fd::RawFd,
fd: F,
) -> &mut Self {
use std::os::fd::AsRawFd;
use std::os::unix::process::CommandExt;

let cvt = |x| if x == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) };

let fd = fd.into();
if fd.as_raw_fd() == newfd {
// if fd is already where we want it, just turn off FD_CLOEXEC
// SAFETY: io-safe: we have ownership over fd
cvt(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_SETFD, 0) })
.expect("disabling CLOEXEC failed");
// we still unconditionally set the pre_exec function, since it captures
// `fd`, and we want to ensure that it stays open until the fork
}
let pre_exec = move || {
if fd.as_raw_fd() != newfd {
// set newfd to point to the same file as fd
// SAFETY: io-"safe": newfd is. not necessarily an unused fd.
// however, we're
cvt(unsafe { libc::dup2(fd.as_raw_fd(), newfd) })?;
}
Ok(())
};
// SAFETY: dup2 is pre-exec-safe
unsafe { self.cmd.pre_exec(pre_exec) };
self
}

/// Run the constructed command and assert that it is successfully run.
#[track_caller]
pub fn run(&mut self) -> CompletedProcess {
Expand Down
16 changes: 16 additions & 0 deletions src/tools/run-make-support/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ macro_rules! impl_common_helpers {
self
}

/// Set an auxiliary stream passed to the process, besides the stdio streams.
///
/// Use with caution - ideally, only set one aux fd; if there are multiple,
/// their old `fd` may overlap with another's `newfd`, and thus will break.
/// If you need more than 1 auxiliary file descriptor, rewrite this function
/// to be able to support that.
#[cfg(unix)]
pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
&mut self,
newfd: std::os::fd::RawFd,
fd: F,
) -> &mut Self {
self.cmd.set_aux_fd(newfd, fd);
self
}

/// Run the constructed command and assert that it is successfully run.
#[track_caller]
pub fn run(&mut self) -> crate::command::CompletedProcess {
Expand Down
26 changes: 14 additions & 12 deletions tests/run-make/jobserver-error/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@ fn main() {
.run_fail()
.stderr_utf8();
diff().expected_file("cannot_open_fd.stderr").actual_text("actual", out).run();
// FIXME(Oneirical): Find how to use file descriptor "3" with run-make-support
// and pipe /dev/null into it.
// Original lines:
//
// bash -c 'echo "fn main() {}" | makeflags="--jobserver-auth=3,3" $(rustc) - 3</dev/null' \
// 2>&1 | diff not_a_pipe.stderr -

let out = rustc()
.stdin("fn main() {}")
.input("-")
.env("MAKEFLAGS", "--jobserver-auth=3,3")
.set_aux_fd(3, std::fs::File::open("/dev/null").unwrap())
.run()
.stderr_utf8();
diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run();

// # this test randomly fails, see https://github.com/rust-lang/rust/issues/110321
// disabled:
// bash -c 'echo "fn main() {}" | makeflags="--jobserver-auth=3,3" $(rustc) - \
// 3< <(cat /dev/null)' 2>&1 | diff poisoned_pipe.stderr -
//
// let (readpipe, _) = std::pipe::pipe().unwrap();
// let out = rustc()
// .stdin("fn main() {}")
// .input("-")
// .env("MAKEFLAGS", "--jobserver-auth=0,0")
// .env("MAKEFLAGS", "--jobserver-auth=3,3")
// .set_fd3(readpipe)
// .run()
// .stderr_utf8();
// diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run();
// diff().expected_file("poisoned_pipe.stderr").actual_text("actual", out).run();
}

0 comments on commit 77c21c5

Please sign in to comment.