Document unsafe contracts and stop reusing poisoned state

This commit is contained in:
Samuel Onoja committed 2026-10-22 01:28:03 +01:00
1 parent a7fcd69897
commit f2e728b503
46 files changed
+377 -45

No files matched your search

+6 -1
View File
@@ -247,8 +247,9 @@ pub fn command(action: &Action, socket: &Path, json_output: bool) -> Result<(),
static CHILD: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
extern "C" fn terminate(signal: i32) {
let pid = CHILD.load(std::sync::atomic::Ordering::Relaxed);
// SAFETY: kill is async-signal-safe; the PID belongs to this wrapper's child.
if pid > 0 {
// SAFETY: kill is async-signal-safe and has no pointer arguments; pid names the wrapper
// child.
unsafe {
libc::kill(pid, signal);
}
@@ -325,6 +326,8 @@ pub fn run(
// Terminal-generated signals reach both processes in the shell's job group.
// The wrapper waits for the actual child result; the child resets inherited
// dispositions before exec. SIGTSTP/SIGCONT retain normal job control.
// SAFETY: The handler only loads an atomic PID and calls kill. The pre_exec hook only resets
// signal dispositions, without allocation or locks.
unsafe {
libc::signal(libc::SIGINT, libc::SIG_IGN);
libc::signal(libc::SIGQUIT, libc::SIG_IGN);
@@ -442,6 +445,8 @@ pub fn run(
}
if let Some(signal) = status.signal() {
// Preserve signal termination as well as the conventional shell status.
// SAFETY: signal and raise use a signal obtained from the child exit status and have no
// borrowed memory.
unsafe {
libc::signal(signal, libc::SIG_DFL);
libc::raise(signal);
+1
View File
@@ -32,6 +32,7 @@ impl Read for Output {
};
// The pipe has exactly one reader. Once readable (or hung up), a
// pipe read returns available bytes (or EOF) without filling bytes.
// SAFETY: fd is a live pollfd and the count of one matches its writable storage.
let result = unsafe { libc::poll(&mut fd, 1, 20) };
if result > 0 {
return self.pipe.read(bytes);
+4
View File
@@ -13,6 +13,8 @@ pub(crate) fn run() -> Result<(), Box<dyn std::error::Error>> {
.filter(|fd| *fd >= 3)
{
// These session-helper descriptors must never reach ordinary startup apps.
// SAFETY: fcntl receives integer descriptor flags, without pointer arguments; invalid
// descriptors return an error.
unsafe {
let flags = libc::fcntl(fd, libc::F_GETFD);
if flags < 0 || libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) < 0 {
@@ -76,6 +78,8 @@ pub(crate) fn run() -> Result<(), Box<dyn std::error::Error>> {
.env_remove("FERESE_PUBLIC_WAYLAND_DISPLAY");
// Only signal-safe calls run in the child before exec. A pending launcher
// dies with this helper, while apps already launched by GIO remain independent.
// SAFETY: The child hook uses only async-signal-safe prctl, getppid and _exit before
// exec.
unsafe {
command.pre_exec(move || {
if libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGTERM) != 0 {