#![cfg(unix)]
pub mod altstack {
use libc::{
MAP_ANON, MAP_FAILED, MAP_PRIVATE, PROT_READ, PROT_WRITE, SS_DISABLE, mmap, sigaltstack,
stack_t,
};
use std::{io, mem::MaybeUninit, ptr};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum State {
Disabled,
Enabled {
size: usize,
},
}
impl Default for State {
fn default() -> Self {
Self::Enabled { size: 8 * 1024 }
}
}
pub fn set(state: State) -> io::Result<()> {
match state {
State::Disabled => {
let ss = stack_t {
ss_flags: SS_DISABLE,
ss_sp: ptr::null_mut(),
ss_size: 0,
};
let result = unsafe { sigaltstack(&raw const ss, ptr::null_mut()) };
if result != 0 {
return Err(io::Error::last_os_error());
}
}
State::Enabled { size } => {
let ptr = unsafe {
mmap(
ptr::null_mut(),
size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0,
)
};
if ptr == MAP_FAILED {
return Err(io::Error::last_os_error());
}
let ss = stack_t {
ss_sp: ptr,
ss_size: size,
ss_flags: 0,
};
let result = unsafe { sigaltstack(&raw const ss, ptr::null_mut()) };
if result != 0 {
return Err(io::Error::last_os_error());
}
}
}
Ok(())
}
pub fn get() -> io::Result<State> {
let mut current = MaybeUninit::uninit();
let result = unsafe { sigaltstack(ptr::null(), current.as_mut_ptr()) };
if result != 0 {
return Err(io::Error::last_os_error());
}
let current = unsafe { current.assume_init() };
let enabled = current.ss_flags & SS_DISABLE == 0;
let state = if enabled {
State::Enabled {
size: current.ss_size,
}
} else {
State::Disabled
};
Ok(state)
}
}