Skip to content

Commit

Permalink
add safety comments to signal code
Browse files Browse the repository at this point in the history
  • Loading branch information
squell committed Sep 2, 2024
1 parent fb0d3cb commit 70a8cdd
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/system/signal/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ impl SignalInfo {
/// Gets the PID that sent the signal.
pub(crate) fn pid(&self) -> ProcessId {
// FIXME: some signals don't set si_pid.
//
// SAFETY: this just fetches the `si_pid` field; since this is an integer,
// even if the information is nonsense it will not cause UB. Note that
// that a `ProcessId` does not have as type invariant that it always holds a valid
// process id, only that it is the appropriate type for storing such ids.
unsafe { self.info.si_pid() }
}

Expand Down
9 changes: 9 additions & 0 deletions src/system/signal/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ impl SignalAction {
pub(super) fn register(&self, signal: SignalNumber) -> io::Result<Self> {
let mut original_action = MaybeUninit::<Self>::zeroed();

// SAFETY: `sigaction` expects a valid pointer, which we provide; the typecast is valid
// since SignalAction is a repr(transparent) newtype struct.
cerr(unsafe { libc::sigaction(signal, &self.raw, original_action.as_mut_ptr().cast()) })?;

// SAFETY: `sigaction` will have properly initialized `original_action`.
Ok(unsafe { original_action.assume_init() })
}
}
Expand All @@ -59,25 +62,31 @@ impl SignalSet {
pub(crate) fn empty() -> io::Result<Self> {
let mut set = MaybeUninit::<Self>::zeroed();

// SAFETY: same as above
cerr(unsafe { libc::sigemptyset(set.as_mut_ptr().cast()) })?;

// SAFETY: `sigemptyset` will have initialized `set`
Ok(unsafe { set.assume_init() })
}

/// Create a set containing all the signals.
pub(crate) fn full() -> io::Result<Self> {
let mut set = MaybeUninit::<Self>::zeroed();

// SAFETY: same as above
cerr(unsafe { libc::sigfillset(set.as_mut_ptr().cast()) })?;

// SAFETY: `sigfillset` will have initialized `set`
Ok(unsafe { set.assume_init() })
}

fn sigprocmask(&self, how: libc::c_int) -> io::Result<Self> {
let mut original_set = MaybeUninit::<Self>::zeroed();

// SAFETY: same as above
cerr(unsafe { libc::sigprocmask(how, &self.raw, original_set.as_mut_ptr().cast()) })?;

// SAFETY: `sigprocmask` will have initialized `set`
Ok(unsafe { original_set.assume_init() })
}

Expand Down
5 changes: 5 additions & 0 deletions src/system/signal/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ impl SignalStream {
pub(crate) fn recv(&self) -> io::Result<SignalInfo> {
let mut info = MaybeUninit::<SignalInfo>::uninit();
let fd = self.rx.as_raw_fd();
// SAFETY: type invariant for `SignalStream` ensures that `fd` is a valid file descriptor;
// furthermore, `info` is a valid pointer to `siginfo_t` (by virtue of `SignalInfo` being a
// transparent newtype for it), which has room for `SignalInfo::SIZE` bytes.
let bytes = cerr(unsafe { libc::recv(fd, info.as_mut_ptr().cast(), SignalInfo::SIZE, 0) })?;

if bytes as usize != SignalInfo::SIZE {
Expand Down Expand Up @@ -92,6 +95,8 @@ pub(crate) fn register_handlers<const N: usize>(
})?;
}

// SAFETY: if the above for-loop has terminated, every handler will have
// been written to via "MaybeUnit::new", and so is initialized.
Ok(handlers.map(|(_, handler)| unsafe { handler.assume_init() }))
}

Expand Down

0 comments on commit 70a8cdd

Please sign in to comment.