Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2b44a3d

Browse files
committedJan 13, 2025
Auto merge of rust-lang#135461 - jieyouxu:migrate-jobserver-errors, r=<try>
tests: Port `jobserver-error.rs` to rmake.rs Part of rust-lang#121876. This PR ports `jobserver-error.rs` to rmake.rs, and is basically rust-lang#128789 slightly adjusted. Namely, `set_aux_fd` is made `unsafe`, alongside some doc updates. The complexity involved here is mostly how to get `/dev/null/` piping to fd 3 working with std `Command`, whereas with a shell this is much easier (as is evident with the `Makefile` version). Supersedes rust-lang#128789. This PR is co-authored with `@Oneirical` and `@coolreader18.` r? `@ghost` try-job: aarch64-gnu try-job: i686-gnu-1 try-job: x86_64-gnu-debug try-job: x86_64-gnu-llvm-18-1
2 parents 2ae9916 + aaddf77 commit 2b44a3d

File tree

5 files changed

+119
-18
lines changed

5 files changed

+119
-18
lines changed
 

‎src/tools/run-make-support/src/command.rs

+47
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,53 @@ impl Command {
151151
self
152152
}
153153

154+
/// Set an auxiliary stream passed to the process, besides the stdio streams.
155+
///
156+
/// # Safety
157+
///
158+
/// Use with caution! Ideally, only set one aux fd; if there are multiple, their old `fd` may
159+
/// overlap with another's `new_fd`, and may break. The caller must make sure this is not the
160+
/// case.
161+
#[cfg(unix)]
162+
pub unsafe fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
163+
&mut self,
164+
new_fd: std::os::fd::RawFd,
165+
fd: F,
166+
) -> &mut Self {
167+
// NOTE: If more than 1 auxiliary file descriptor is needed, this function should be
168+
// rewritten.
169+
170+
use std::os::fd::AsRawFd;
171+
use std::os::unix::process::CommandExt;
172+
173+
let cvt = |x| if x == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) };
174+
175+
let fd = fd.into();
176+
if fd.as_raw_fd() == new_fd {
177+
// If the new file descriptor is already the same as fd, just turn off `FD_CLOEXEC`.
178+
179+
// SAFETY(io-safety): `fd` is already owned.
180+
cvt(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_SETFD, 0) })
181+
.expect("disabling CLOEXEC failed");
182+
// The `pre_exec` function should be unconditionally set, since it captures `fd`, and
183+
// this ensures that it stays open until the fork.
184+
}
185+
let pre_exec = move || {
186+
if fd.as_raw_fd() != new_fd {
187+
// SAFETY(io-safety): `new_fd` is not necessarily an unused fd. However, we're
188+
// ensuring that `new_fd` will now refer to the same file descriptor as `fd`, which
189+
// is safe as long as we manage the lifecycle of both descriptors correctly. This
190+
// operation will replace the file descriptor referred to by `new_fd` with the one
191+
// from `fd`, allowing for shared access to the same underlying file or resource.
192+
cvt(unsafe { libc::dup2(fd.as_raw_fd(), new_fd) })?;
193+
}
194+
Ok(())
195+
};
196+
// SAFETY(pre-exec-safe): `dup2` is pre-exec-safe.
197+
unsafe { self.cmd.pre_exec(pre_exec) };
198+
self
199+
}
200+
154201
/// Run the constructed command and assert that it is successfully run.
155202
///
156203
/// By default, std{in,out,err} are [`Stdio::piped()`].

‎src/tools/run-make-support/src/macros.rs

+17
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,23 @@ macro_rules! impl_common_helpers {
104104
self
105105
}
106106

107+
/// Set an auxiliary stream passed to the process, besides the stdio streams.
108+
///
109+
/// # Safety
110+
///
111+
/// Use with caution! Ideally, only set one aux fd; if there are multiple, their old
112+
/// `fd` may overlap with another's `new_fd`, and may break. The caller must make sure
113+
/// this is not the case.
114+
#[cfg(unix)]
115+
pub unsafe fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
116+
&mut self,
117+
new_fd: std::os::fd::RawFd,
118+
fd: F,
119+
) -> &mut Self {
120+
self.cmd.set_aux_fd(new_fd, fd);
121+
self
122+
}
123+
107124
/// Run the constructed command and assert that it is successfully run.
108125
#[track_caller]
109126
pub fn run(&mut self) -> crate::command::CompletedProcess {
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
run-make/cat-and-grep-sanity-check/Makefile
22
run-make/extern-fn-reachable/Makefile
3-
run-make/jobserver-error/Makefile
43
run-make/split-debuginfo/Makefile
54
run-make/symbol-mangling-hashed/Makefile
65
run-make/translation/Makefile

‎tests/run-make/jobserver-error/Makefile

-17
This file was deleted.
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! If the environment variables contain an invalid `jobserver-auth`, this used to cause an ICE
2+
//! until this was fixed in [do not panic on failure to acquire jobserver token
3+
//! #109694](https://github.com/rust-lang/rust/pull/109694).
4+
//!
5+
//! Proper handling has been added, and this test checks that helpful warnings and errors are
6+
//! printed instead in case of a wrong jobserver. See
7+
//! <https://github.com/rust-lang/rust/issues/46981>.
8+
9+
//@ only-linux
10+
//@ ignore-cross-compile
11+
12+
use run_make_support::{diff, rustc};
13+
14+
fn main() {
15+
let out = rustc()
16+
.stdin_buf(("fn main() {}").as_bytes())
17+
.env("MAKEFLAGS", "--jobserver-auth=5,5")
18+
.run_fail()
19+
.stderr_utf8();
20+
diff().expected_file("cannot_open_fd.stderr").actual_text("actual", out).run();
21+
22+
// SAFETY(io-safety): we don't have overlapping fd 3.
23+
let out = unsafe {
24+
rustc()
25+
.stdin_buf(("fn main() {}").as_bytes())
26+
.input("-")
27+
.env("MAKEFLAGS", "--jobserver-auth=3,3")
28+
.set_aux_fd(3, std::fs::File::open("/dev/null").unwrap())
29+
.run()
30+
.stderr_utf8()
31+
};
32+
diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run();
33+
34+
// FIXME(#110321): this case is spurious because:
35+
//
36+
// > the jobserver helper thread launched here gets starved out and doesn't run, while the
37+
// > coordinator thread continually processes work using the implicit jobserver token, never
38+
// > yielding long enough for the jobserver helper to do its work (and process the error).
39+
//
40+
// but is not necessarily worth fixing as it might require changing coordinator behavior that
41+
// might regress performance. See discussion at
42+
// <https://github.com/rust-lang/rust/issues/110321#issuecomment-1636914956>.
43+
44+
//let (readpipe, _) = std::pipe::pipe().unwrap();
45+
//let out = unsafe {
46+
// rustc()
47+
// .stdin("fn main() {}")
48+
// .input("-")
49+
// .env("MAKEFLAGS", "--jobserver-auth=3,3")
50+
// .set_aux_fd(3, readpipe)
51+
// .run()
52+
// .stderr_utf8()
53+
//};
54+
//diff().expected_file("poisoned_pipe.stderr").actual_text("actual", out).run();
55+
}

0 commit comments

Comments
 (0)
Failed to load comments.