Skip to content

Commit

Permalink
unix_sigpipe: Add test for SIGPIPE disposition in child processes
Browse files Browse the repository at this point in the history
For robustness, also test the disposition in our own process even if
tests in `tests/ui/attributes/unix_sigpipe` already covers it.
  • Loading branch information
Enselic committed Feb 25, 2024
1 parent 21033f6 commit 527be25
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
15 changes: 15 additions & 0 deletions tests/run-make/sigpipe-in-child-processes/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ignore-cross-compile because we run the compiled code
# only-unix

# See main.rs for a description of this test.

include ../tools.mk

all:
$(RUSTC) assert-sigpipe-disposition.rs -o $(TMPDIR)/assert-sigpipe-disposition;
for revision in default sig_dfl sig_ign inherit; do \
echo -n "Testing revision $$revision ... "; \
$(RUSTC) main.rs --cfg $$revision -o $(TMPDIR)/main.$$revision || exit 1; \
$(TMPDIR)/main.$$revision $(TMPDIR)/assert-sigpipe-disposition || exit 1; \
echo "ok"; \
done
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![feature(start, rustc_private)]

extern crate libc;

// Use #[start] so we don't have a runtime that messes with SIGPIPE.
#[start]
fn start(argc: isize, argv: *const *const u8) -> isize {
assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg");
let expected =
match unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const i8) }.to_str().unwrap() {
"SIG_IGN" => libc::SIG_IGN,
"SIG_DFL" => libc::SIG_DFL,
arg => panic!("Must pass SIG_IGN or SIG_DFL as first arg. Got: {}", arg),
};

let actual = unsafe {
let mut actual: libc::sigaction = std::mem::zeroed();
libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
actual.sa_sigaction
};

assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs");

return 0;
}
51 changes: 51 additions & 0 deletions tests/run-make/sigpipe-in-child-processes/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Checks the signal disposition of `SIGPIPE` in child processes, and in our own
// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is
// the default. But there is a difference in how `SIGPIPE` is treated in child
// processes with and without the attribute. Search for
// `unix_sigpipe_attr_specified()` in the code base to learn more.
//
// Note that there are many other tests for `unix_sigpipe` in
// tests/ui/attributes/unix_sigpipe.

#![feature(rustc_private)]
#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))]

extern crate libc;

#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")]
#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")]
#[cfg_attr(inherit, unix_sigpipe = "inherit")]
fn main() {
// By default, we get SIG_IGN but the child gets SIG_DFL.
#[cfg(default)]
let (we_expect, child_expects) = (libc::SIG_IGN, libc::SIG_DFL);

// With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too.
#[cfg(sig_dfl)]
let (we_expect, child_expects) = (libc::SIG_DFL, libc::SIG_DFL);

// With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too.
#[cfg(sig_ign)]
let (we_expect, child_expects) = (libc::SIG_IGN, libc::SIG_IGN);

// With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too.
#[cfg(inherit)]
let (we_expect, child_expects) = (libc::SIG_DFL, libc::SIG_DFL);

let actual = unsafe {
let mut actual: libc::sigaction = std::mem::zeroed();
libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
actual.sa_sigaction
};
assert_eq!(actual, we_expect, "we did not get the SIGPIPE disposition we expect");

let child_program = std::env::args().nth(1).unwrap();
let child_expects = match child_expects {
libc::SIG_DFL => "SIG_DFL",
libc::SIG_IGN => "SIG_IGN",
_ => unreachable!(),
};
assert!(
std::process::Command::new(child_program).arg(child_expects).status().unwrap().success()
);
}

0 comments on commit 527be25

Please sign in to comment.