Fix sigaction Undefind Behavior
Rust does not allow a `fn`-pointer to be null. This fixes that, while luckily doing it in a way that leaves system calls backwards-compatible :)
This commit is contained in:
+9
-10
@@ -107,22 +107,21 @@ impl DerefMut for Packet {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct SigAction {
|
||||
pub sa_handler: extern "C" fn(usize),
|
||||
pub sa_handler: Option<extern "C" fn(usize)>,
|
||||
pub sa_mask: [u64; 2],
|
||||
pub sa_flags: usize,
|
||||
}
|
||||
|
||||
impl Default for SigAction {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sa_handler: unsafe { mem::transmute(0usize) },
|
||||
sa_mask: [0; 2],
|
||||
sa_flags: 0,
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
unsafe fn _assert_size_of_function_is_sane() {
|
||||
// Transmuting will complain *at compile time* if sizes differ.
|
||||
// Rust forbids a fn-pointer from being 0 so to allow SIG_DFL to
|
||||
// exist, we use Option<extern "C" fn(usize)> which will mean 0
|
||||
// becomes None
|
||||
let _ = mem::transmute::<Option<extern "C" fn(usize)>, usize>(None);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
|
||||
@@ -409,3 +409,62 @@ fn unlink() {
|
||||
fn sched_yield() {
|
||||
assert_eq!(dbg!(crate::sched_yield()), Ok(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sigaction() {
|
||||
use std::{
|
||||
mem,
|
||||
sync::atomic::{AtomicBool, Ordering}
|
||||
};
|
||||
|
||||
let child = unsafe { dbg!(crate::clone(0)).unwrap() };
|
||||
|
||||
if child == 0 {
|
||||
static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
let pid = dbg!(crate::getpid()).unwrap();
|
||||
|
||||
extern "C" fn hello_im_a_signal_handler(signal: usize) {
|
||||
assert_eq!(dbg!(signal), crate::SIGUSR1);
|
||||
SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
let my_signal_handler = crate::SigAction {
|
||||
sa_handler: Some(hello_im_a_signal_handler),
|
||||
..Default::default()
|
||||
};
|
||||
dbg!(crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None)).unwrap();
|
||||
|
||||
dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // calls handler
|
||||
|
||||
let mut old_signal_handler = crate::SigAction::default();
|
||||
dbg!(crate::sigaction(
|
||||
crate::SIGUSR1,
|
||||
Some(&crate::SigAction {
|
||||
sa_handler: unsafe { mem::transmute::<usize, Option<extern "C" fn(usize)>>(crate::SIG_IGN) },
|
||||
..Default::default()
|
||||
}),
|
||||
Some(&mut old_signal_handler)
|
||||
)).unwrap();
|
||||
assert_eq!(my_signal_handler, old_signal_handler);
|
||||
|
||||
dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // does nothing
|
||||
|
||||
dbg!(crate::sigaction(
|
||||
crate::SIGUSR1,
|
||||
Some(&crate::SigAction {
|
||||
sa_handler: unsafe { mem::transmute::<usize, Option<extern "C" fn(usize)>>(crate::SIG_DFL) },
|
||||
..Default::default()
|
||||
}),
|
||||
Some(&mut old_signal_handler)
|
||||
)).unwrap();
|
||||
|
||||
dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // actually exits
|
||||
} else {
|
||||
let mut status = 0;
|
||||
dbg!(crate::waitpid(child, &mut status, 0)).unwrap();
|
||||
|
||||
assert!(crate::wifsignaled(status));
|
||||
assert_eq!(crate::wtermsig(status), crate::SIGUSR1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user