From 527be25797783dbdb107ab7b02d2732c95a1f569 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 24 Feb 2024 16:48:24 +0100 Subject: [PATCH] unix_sigpipe: Add test for SIGPIPE disposition in child processes For robustness, also test the disposition in our own process even if tests in `tests/ui/attributes/unix_sigpipe` already covers it. --- .../sigpipe-in-child-processes/Makefile | 15 ++++++ .../assert-sigpipe-disposition.rs | 25 +++++++++ .../sigpipe-in-child-processes/main.rs | 51 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 tests/run-make/sigpipe-in-child-processes/Makefile create mode 100644 tests/run-make/sigpipe-in-child-processes/assert-sigpipe-disposition.rs create mode 100644 tests/run-make/sigpipe-in-child-processes/main.rs diff --git a/tests/run-make/sigpipe-in-child-processes/Makefile b/tests/run-make/sigpipe-in-child-processes/Makefile new file mode 100644 index 0000000000000..acdca1a416f71 --- /dev/null +++ b/tests/run-make/sigpipe-in-child-processes/Makefile @@ -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 diff --git a/tests/run-make/sigpipe-in-child-processes/assert-sigpipe-disposition.rs b/tests/run-make/sigpipe-in-child-processes/assert-sigpipe-disposition.rs new file mode 100644 index 0000000000000..8c0b8149b819b --- /dev/null +++ b/tests/run-make/sigpipe-in-child-processes/assert-sigpipe-disposition.rs @@ -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; +} diff --git a/tests/run-make/sigpipe-in-child-processes/main.rs b/tests/run-make/sigpipe-in-child-processes/main.rs new file mode 100644 index 0000000000000..30c1043538c5d --- /dev/null +++ b/tests/run-make/sigpipe-in-child-processes/main.rs @@ -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() + ); +}