Skip to content

Commit 0dc26de

Browse files
committed
unix_sigpipe: Add test for SIGPIPE disposition in child processes
For robustness, also test the disposition in our own process even if other tests in `tests/ui/attributes/unix_sigpipe` already covers it.
1 parent bf60149 commit 0dc26de

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// It is UB to unwind out of `fn start()` according to
2+
// https://doc.rust-lang.org/beta/unstable-book/language-features/start.html so
3+
// panic with abort to avoid UB:
4+
//@ compile-flags:-C panic=abort
5+
//@ no-prefer-dynamic
6+
7+
#![crate_type = "bin"]
8+
#![feature(start, rustc_private)]
9+
10+
extern crate libc;
11+
12+
// Use #[start] so we don't have a runtime that messes with SIGPIPE.
13+
#[start]
14+
fn start(argc: isize, argv: *const *const u8) -> isize {
15+
assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg");
16+
let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
17+
.to_str()
18+
.unwrap();
19+
20+
let expected = match arg1 {
21+
"SIG_IGN" => libc::SIG_IGN,
22+
"SIG_DFL" => libc::SIG_DFL,
23+
arg => panic!("Must pass SIG_IGN or SIG_DFL as first arg. Got: {}", arg),
24+
};
25+
26+
let actual = unsafe {
27+
let mut actual: libc::sigaction = std::mem::zeroed();
28+
libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
29+
actual.sa_sigaction
30+
};
31+
32+
assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs");
33+
34+
0
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//@ revisions: default sig_dfl sig_ign inherit
2+
//@ aux-build:assert-sigpipe-disposition-bin.rs
3+
//@ aux-build:sigpipe-utils.rs
4+
//@ ignore-cross-compile because we run the compiled code
5+
//@ only-unix because SIGPIPE is a unix thing
6+
//@ run-pass
7+
8+
// Checks the signal disposition of `SIGPIPE` in child processes, and in our own
9+
// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is
10+
// the default. But there is a difference in how `SIGPIPE` is treated in child
11+
// processes with and without the attribute. Search for
12+
// `unix_sigpipe_attr_specified()` in the code base to learn more.
13+
14+
#![feature(rustc_private)]
15+
#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))]
16+
17+
extern crate libc;
18+
19+
// We need `aux-build` for `assert-sigpipe-disposition-bin`, and `compiletest`
20+
// gets confused if we use both `aux-build` and `aux-crate` in the same test, so
21+
// we need to use the old style of bringing `sigpipe_utils` in scope.
22+
extern crate sigpipe_utils;
23+
24+
use sigpipe_utils::*;
25+
26+
#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")]
27+
#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")]
28+
#[cfg_attr(inherit, unix_sigpipe = "inherit")]
29+
fn main() {
30+
// By default, we get SIG_IGN but the child gets SIG_DFL.
31+
#[cfg(default)]
32+
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL");
33+
34+
// With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too.
35+
#[cfg(sig_dfl)]
36+
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
37+
38+
// With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too.
39+
#[cfg(sig_ign)]
40+
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN");
41+
42+
// With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too.
43+
#[cfg(inherit)]
44+
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
45+
46+
assert_sigpipe_handler(we_expect);
47+
48+
assert!(
49+
std::process::Command::new("./auxiliary/assert-sigpipe-disposition-bin")
50+
.arg(child_expects)
51+
.status()
52+
.unwrap()
53+
.success()
54+
);
55+
}

0 commit comments

Comments
 (0)