shadowsocks/shadowsocks-rust · warning

errno

Error message

errno

What it means

Panic in daemonize's errno(): std::io::Error::last_os_error().raw_os_error() returned None, meaning the last OS error had no raw errno. This should be nearly impossible (raw_os_error is None only for constructed io::Errors), and expect('errno') is an internal invariant check used by check_err and execute_child when reporting daemonization failures.

Source

Thrown at src/daemonize/daemonize/error.rs:160

impl Num for i64 {
    fn is_err(&self) -> bool {
        *self == -1
    }
}

impl Num for isize {
    fn is_err(&self) -> bool {
        *self == -1
    }
}

pub fn check_err<N: Num, F: FnOnce(Errno) -> ErrorKind>(ret: N, f: F) -> Result<N, ErrorKind> {
    if ret.is_err() { Err(f(errno())) } else { Ok(ret) }
}

pub fn errno() -> Errno {
    std::io::Error::last_os_error().raw_os_error().expect("errno")
}

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Call errno() immediately after the failing syscall, before other io operations
  2. Inspect preceding code that may have set a non-OS io::Error and handle it separately
  3. Replace expect with a fallback error kind (ErrorKind::Other) instead of panicking in a daemonization path
  4. Run the daemonization in the foreground with logging to capture the sequence of failing syscalls

Example fix

// before
pub fn errno() -> Errno {
    std::io::Error::last_os_error().raw_os_error().expect("errno")
}
// after
pub fn errno() -> Errno {
    std::io::Error::last_os_error()
        .raw_os_error()
        .unwrap_or(libc::EIO)
}
Defensive patterns

Strategy: fallback

Validate before calling

// not applicable: errno() depends on thread-local OS state, not caller inputs

Type guard

fn last_raw_errno() -> Option<i32> {
    std::io::Error::last_os_error().raw_os_error()
}

Try / catch

// expect() panics cannot be caught in-process except via catch_unwind; prefer reading the errno yourself
let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(libc::EIO);

Prevention

When it happens

Trigger: check_err or execute_child detects a failed syscall return and calls errno(), but last_os_error() yields an io::Error whose raw_os_error() is None (non-OS io::Error active in the thread's error slot).

Common situations: A prior library call stored a custom (non-OS) io::Error in the thread-local last-error slot; interleaving with other FFI/io code that clobbers the last error between syscall failure and errno() read.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09). Data as JSON: /api/errors/31bbd3504cb8397e. Report an issue: GitHub.