Skip to content

Commit

Permalink
Rollup merge of rust-lang#121573 - Enselic:sigpipe-child-process, r=M…
Browse files Browse the repository at this point in the history
…ark-Simulacrum

unix_sigpipe: Add test for SIGPIPE disposition in child processes

To make it clearer what the impact would be to stop using `SIG_IGN` and instead use a noop handler, like suggested [here](rust-lang#62569 (comment)) and implemented [here](rust-lang#121578).

Part of rust-lang#97889
  • Loading branch information
matthiaskrgr authored Mar 10, 2024
2 parents 3521a2f + 527be25 commit 620607d
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 620607d

Please sign in to comment.