Skip to content

Commit 77c21c5

Browse files
authored
Merge pull request #2 from coolreader18/runmake-fd3
Add fd3 support to runmake
2 parents 97091f2 + 0eb50a0 commit 77c21c5

File tree

5 files changed

+72
-12
lines changed

5 files changed

+72
-12
lines changed

Diff for: Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3149,6 +3149,7 @@ dependencies = [
31493149
"bstr",
31503150
"build_helper",
31513151
"gimli 0.31.0",
3152+
"libc",
31523153
"object 0.36.2",
31533154
"regex",
31543155
"similar",

Diff for: src/tools/run-make-support/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ similar = "2.5.0"
1010
wasmparser = { version = "0.214", default-features = false, features = ["std"] }
1111
regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
1212
gimli = "0.31.0"
13+
libc = "0.2"
1314
build_helper = { path = "../build_helper" }

Diff for: src/tools/run-make-support/src/command.rs

+40
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,46 @@ impl Command {
104104
self
105105
}
106106

107+
/// Set an auxiliary stream passed to the process, besides the stdio streams.
108+
///
109+
/// Use with caution - ideally, only set one aux fd; if there are multiple,
110+
/// their old `fd` may overlap with another's `newfd`, and thus will break.
111+
/// If you need more than 1 auxiliary file descriptor, rewrite this function
112+
/// to be able to support that.
113+
#[cfg(unix)]
114+
pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
115+
&mut self,
116+
newfd: std::os::fd::RawFd,
117+
fd: F,
118+
) -> &mut Self {
119+
use std::os::fd::AsRawFd;
120+
use std::os::unix::process::CommandExt;
121+
122+
let cvt = |x| if x == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) };
123+
124+
let fd = fd.into();
125+
if fd.as_raw_fd() == newfd {
126+
// if fd is already where we want it, just turn off FD_CLOEXEC
127+
// SAFETY: io-safe: we have ownership over fd
128+
cvt(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_SETFD, 0) })
129+
.expect("disabling CLOEXEC failed");
130+
// we still unconditionally set the pre_exec function, since it captures
131+
// `fd`, and we want to ensure that it stays open until the fork
132+
}
133+
let pre_exec = move || {
134+
if fd.as_raw_fd() != newfd {
135+
// set newfd to point to the same file as fd
136+
// SAFETY: io-"safe": newfd is. not necessarily an unused fd.
137+
// however, we're
138+
cvt(unsafe { libc::dup2(fd.as_raw_fd(), newfd) })?;
139+
}
140+
Ok(())
141+
};
142+
// SAFETY: dup2 is pre-exec-safe
143+
unsafe { self.cmd.pre_exec(pre_exec) };
144+
self
145+
}
146+
107147
/// Run the constructed command and assert that it is successfully run.
108148
#[track_caller]
109149
pub fn run(&mut self) -> CompletedProcess {

Diff for: src/tools/run-make-support/src/macros.rs

+16
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,22 @@ macro_rules! impl_common_helpers {
8080
self
8181
}
8282

83+
/// Set an auxiliary stream passed to the process, besides the stdio streams.
84+
///
85+
/// Use with caution - ideally, only set one aux fd; if there are multiple,
86+
/// their old `fd` may overlap with another's `newfd`, and thus will break.
87+
/// If you need more than 1 auxiliary file descriptor, rewrite this function
88+
/// to be able to support that.
89+
#[cfg(unix)]
90+
pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
91+
&mut self,
92+
newfd: std::os::fd::RawFd,
93+
fd: F,
94+
) -> &mut Self {
95+
self.cmd.set_aux_fd(newfd, fd);
96+
self
97+
}
98+
8399
/// Run the constructed command and assert that it is successfully run.
84100
#[track_caller]
85101
pub fn run(&mut self) -> crate::command::CompletedProcess {

Diff for: tests/run-make/jobserver-error/rmake.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,24 @@ fn main() {
1919
.run_fail()
2020
.stderr_utf8();
2121
diff().expected_file("cannot_open_fd.stderr").actual_text("actual", out).run();
22-
// FIXME(Oneirical): Find how to use file descriptor "3" with run-make-support
23-
// and pipe /dev/null into it.
24-
// Original lines:
25-
//
26-
// bash -c 'echo "fn main() {}" | makeflags="--jobserver-auth=3,3" $(rustc) - 3</dev/null' \
27-
// 2>&1 | diff not_a_pipe.stderr -
22+
23+
let out = rustc()
24+
.stdin("fn main() {}")
25+
.input("-")
26+
.env("MAKEFLAGS", "--jobserver-auth=3,3")
27+
.set_aux_fd(3, std::fs::File::open("/dev/null").unwrap())
28+
.run()
29+
.stderr_utf8();
30+
diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run();
31+
2832
// # this test randomly fails, see https://github.com/rust-lang/rust/issues/110321
29-
// disabled:
30-
// bash -c 'echo "fn main() {}" | makeflags="--jobserver-auth=3,3" $(rustc) - \
31-
// 3< <(cat /dev/null)' 2>&1 | diff poisoned_pipe.stderr -
32-
//
33+
// let (readpipe, _) = std::pipe::pipe().unwrap();
3334
// let out = rustc()
3435
// .stdin("fn main() {}")
3536
// .input("-")
36-
// .env("MAKEFLAGS", "--jobserver-auth=0,0")
37+
// .env("MAKEFLAGS", "--jobserver-auth=3,3")
38+
// .set_fd3(readpipe)
3739
// .run()
3840
// .stderr_utf8();
39-
// diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run();
41+
// diff().expected_file("poisoned_pipe.stderr").actual_text("actual", out).run();
4042
}

0 commit comments

Comments
 (0)