cargo / mio / audit
cargo : mio @ 1.2.0
PE Patrick Elsen signed 2026-05-27 published 2026-05-27

Claims

concurrency-documentedconcurrency-impl-correctconcurrency-impl-documentedconcurrency-impl-safeconcurrency-impl-testedconcurrency-safefilesystem-safehas-binarieshas-build-exechas-fuzz-testshas-install-exechas-integration-testshas-property-testshas-unit-testsimpl-algorithmimpl-concurrencyimpl-cryptoimpl-datastructureimpl-interpreterimpl-jitimpl-parserimpl-protocolis-benignnetwork-safenetwork-secureunsafe-documentedunsafe-minimalunsafe-safeunsafe-testeduses-concurrencyuses-cryptouses-environmentuses-execuses-filesystemuses-interpreteruses-jituses-networkuses-unsafe

Summary

mio 1.2.0 is a cross-platform non-blocking I/O event loop backed by epoll, kqueue, poll(2), WASI poll_oneoff, and Windows IOCP/AFD. One medium-severity finding: 93 of 114 unsafe blocks lack SAFETY comments, reducing auditability. No soundness or security issues were found in the selector implementations, Waker backends, fd-lifetime management, or IOCP bridging layer.

Report

Subject

mio 1.2.0 is a low-level, cross-platform, non-blocking I/O event notification library for Rust. It exposes a readiness model over OS selectors: epoll on Linux/illumos, kqueue on macOS/BSD, poll(2) on other Unix targets, WASI poll_oneoff on WASI, and IOCP via the undocumented AFD driver on Windows. The primary API is Poll (which wraps the OS selector), Registry (for registering/deregistering event sources), Waker (for cross-thread wake), and network types (TcpStream, TcpListener, UdpSocket, Unix domain sockets). It is the foundational I/O event loop used by Tokio and many other async runtimes in the Rust ecosystem.

Methodology

The published crate contents were compared against the upstream Git repository at the commit recorded in .cargo_vcs_info.json using diff -rq. All 59 Rust source files (~7000 LOC) were read in full. The survey covered: all unsafe blocks (157 occurrences across unsafe fn, unsafe impl, and unsafe { ... } forms), all FFI call sites via the libc and windows-sys crates, socket and fd lifetime management, the poll-loop synchronization strategy in the poll(2) backend, the IOCP/AFD bridging layer on Windows, all four Waker backends (eventfd, pipe, kqueue EVFILT_USER, single-threaded), and the kqueue, epoll, and poll selector implementations. The VCS tests/ directory (17 files) was surveyed for test coverage. Tools used: openvet 0.6.0, diff, ripgrep, Python 3 for unsafe-comment analysis.

Results

The published crate contents match the VCS source byte-for-byte for all src/ files. The diff shows only the expected differences: Cargo.toml normalisation by cargo, and the tests/ directory excluded from the published package by the include field.

The crate ships no binaries (justifying has-binaries), no build.rs (justifying has-build-exec and has-install-exec), and no proc macros. No cryptography is used or implemented (justifying uses-crypto and impl-crypto). No environment variables are read at runtime (justifying uses-environment). No child processes are spawned (justifying uses-exec). No JIT or interpreter is present (justifying uses-jit and uses-interpreter). No network protocol, parser, or non-trivial algorithm is implemented (justifying impl-protocol, impl-parser, impl-algorithm, impl-datastructure, impl-interpreter, impl-jit).

The crate uses std::fs::File as an RAII wrapper for raw fds (eventfd, pipe, AFD handle), not for filesystem path operations (justifying uses-filesystem and filesystem-safe). Network socket creation sets SOCK_NONBLOCK|SOCK_CLOEXEC atomically on Linux and via sequential fcntl on Darwin with correct error cleanup, justifying uses-network and network-safe. TLS is not in scope for mio; network-secure is false by design.

unsafe appears in 157 locations (114 unsafe { ... } blocks, 30 unsafe fn, 13 unsafe impl). The structural correctness of the unsafe code was reviewed: fd validity is ensured by the syscall! macro which returns Err on negative return values before the fd is wrapped; OwnedFd and File wrappers provide RAII drop semantics; the Windows SockState arc/pin lifecycle for IOCP overlapped operations is managed through matched into_overlapped/from_overlapped calls with correct reference-count accounting. No soundness issues were identified. However, 93 of the 114 unsafe { ... } blocks carry no // SAFETY: comment (see FINDING-1), justifying unsafe-documented = false. The unsafe is structurally minimal — it is confined to OS syscall boundaries and fd wrapping — justifying unsafe-minimal. No Miri, valgrind, or sanitizer runs were identified in the CI configuration, justifying unsafe-tested = false.

The poll(2) selector uses Mutex, Condvar, and AtomicUsize to synchronize modifications against an in-progress poll(2) call. The IOCP Windows selector uses Arc<Mutex<SockState>> with an AtomicBool polling guard. The Waker is a cross-thread wake primitive (eventfd/pipe/EVFILT_USER), implemented correctly with overflow handling. These justify uses-concurrency, impl-concurrency, concurrency-safe, concurrency-documented, concurrency-impl-safe, concurrency-impl-correct, and concurrency-impl-documented. Loom or ThreadSanitizer testing was not found in CI (justifying concurrency-impl-tested = false).

The package is actively maintained under the tokio-rs organization with a conventional changelog and tagged releases. No obfuscated code, base64 blobs, network endpoints, telemetry, or suspicious branching on host metadata was found, justifying is-benign.

Integration tests (vcs/tests/, 17 files) cover Poll, TCP/UDP/UDS sockets, pipes, and Waker. Unit tests exist in src/. There are no fuzz or property-based tests (justifying has-fuzz-tests and has-property-tests).

Conclusion

One medium-severity finding (FINDING-1) was identified: the majority of unsafe blocks lack // SAFETY: comments, making the unsafe code difficult to audit and maintain. No soundness or security issues were found. The selector implementations for epoll, kqueue, poll(2), and IOCP are structurally consistent with their respective OS interfaces. The Waker implementations correctly handle overflow and platform differences. The concurrency model is coherent and uses standard Rust primitives correctly.

Findings(1)

FINDING-1 quality medium

Majority of unsafe blocks lack SAFETY comments

The majority of unsafe blocks in the codebase lack a // SAFETY: comment explaining the invariants being relied upon. Of 114 unsafe { ... } blocks, 93 have no accompanying safety comment. Coverage is inconsistent: some well-commented blocks appear in kqueue.rs, epoll.rs, uds/mod.rs, and net.rs, while large swaths of the Windows IOCP path (selector.rs, named_pipe.rs, iocp.rs) and the Unix pipe/waker code carry no explanatory comments.

Representative undocumented sites:

  • src/sys/windows/selector.rs:190unsafe { ... } over a block that dereferences a *mut OVERLAPPED cast to the AFD callback function pointer.
  • src/sys/windows/selector.rs:205unsafe { ... } calling Pin::into_inner_unchecked prior to Arc::into_raw.
  • src/sys/windows/iocp.rs:109unsafe { GetQueuedCompletionStatusEx(...) } with no comment on the alignment/length invariants.
  • src/sys/windows/named_pipe.rs:109–127 — four ptr_from_*_overlapped methods rely on the exact #[repr(C)] layout of Inner; a comment explains the field ordering requirement at the struct level but not at the individual unsafe fn call sites.
  • src/sys/unix/pipe.rs:26,43 — raw libc::pipe2/libc::pipe call blocks with no comment.

This does not justify unsafe-safe (the invariants are structurally plausible and no unsoundness was identified), but it does mean the codebase cannot demonstrate that every unsafe block's invariants were consciously evaluated. Justifies unsafe-documented.

Annotations(7)

src

Integration tests covering Poll, TcpStream, TcpListener, UdpSocket, Unix domain sockets, pipes, and Waker live in vcs/tests/ (17 files). The package include list excludes the tests directory, so they are not in the published crate but are present in the VCS checkout. There are also 7 unit tests embedded in src/ (kqueue, iocp, uds). The test suite covers core registration/deregistration paths, event delivery, and regressions but does not include fuzz tests or property-based tests. Justifies has-unit-tests, has-integration-tests, has-fuzz-tests, has-property-tests, and concurrency-impl-tested (no loom or ThreadSanitizer runs were found in CI).

src/sys/unix/net.rs

Socket creation uses SOCK_NONBLOCK|SOCK_CLOEXEC atomically on Linux and equivalent two-step fcntl on Darwin. SO_NOSIGPIPE is set on Apple platforms. The to_socket_addr conversion checks ss_family before casting. mio does not implement any network protocol; it only creates and registers sockets with the OS selector. Network primitives delegate I/O to std::net. Justifies uses-network, network-safe. network-secure is false because mio operates at the socket/fd level and does not enforce TLS.

src/sys/unix/selector/epoll.rs

src/sys/unix/selector/epoll.rs, line 27-70

    pub fn new() -> io::Result<Selector> {
        // SAFETY: `epoll_create1(2)` ensures the fd is valid.
        let ep = unsafe { OwnedFd::from_raw_fd(syscall!(epoll_create1(libc::EPOLL_CLOEXEC))?) };
        Ok(Selector {
            #[cfg(debug_assertions)]
            id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
            ep,
        })
    }

    pub fn try_clone(&self) -> io::Result<Selector> {
        self.ep.try_clone().map(|ep| Selector {
            // It's the same selector, so we use the same id.
            #[cfg(debug_assertions)]
            id: self.id,
            ep,
        })
    }

    pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
        let timeout = timeout
            .map(|to| {
                // `Duration::as_millis` truncates, so round up. This avoids
                // turning sub-millisecond timeouts into a zero timeout, unless
                // the caller explicitly requests that by specifying a zero
                // timeout.
                to.checked_add(Duration::from_nanos(999_999))
                    .unwrap_or(to)
                    .as_millis() as libc::c_int
            })
            .unwrap_or(-1);

        events.clear();
        syscall!(epoll_wait(
            self.ep.as_raw_fd(),
            events.as_mut_ptr(),
            events.capacity() as i32,
            timeout,
        ))
        .map(|n_events| {
            // This is safe because `epoll_wait` ensures that `n_events` are
            // assigned.
            unsafe { events.set_len(n_events as usize) };
        })

Linux epoll selector implementation. The epoll_create1(EPOLL_CLOEXEC) call correctly sets the close-on-exec flag atomically. OwnedFd::from_raw_fd is called with the fd returned by the syscall macro which returns Err on failure, so the fd is valid when from_raw_fd is called. The set_len call after epoll_wait is safe because epoll_wait guarantees it wrote exactly n_events entries into the buffer. Justifies uses-unsafe and unsafe-safe for this path.

src/sys/unix/selector/poll.rs

src/sys/unix/selector/poll.rs, line 192-462

    pub fn select(&self, events: &mut Events, mut timeout: Option<Duration>) -> io::Result<()> {
        events.clear();

        let mut fds = self.fds.lock().unwrap();

        // Keep track of fds that receive POLLHUP or POLLERR (i.e. won't receive further
        // events) and internally deregister them before they are externally deregister'd.  See
        // IoSourceState below to track how the external deregister call will be handled
        // when this state occurs.
        let mut closed_raw_fds = Vec::new();

        loop {
            // Complete all current operations.
            loop {
                if self.waiting_operations.load(Ordering::SeqCst) == 0 {
                    break;
                }

                fds = self.operations_complete.wait(fds).unwrap();
            }

            if self.notify_waker.woken() {
                timeout = Some(Duration::from_secs(0))
            }

            // Perform the poll.
            trace!("Polling on {:?}", &fds);
            let num_events = poll(&mut fds.poll_fds, timeout)?;
            trace!("Poll finished: {:?}", &fds);

            if num_events == 0 {
                return Ok(());
            }

            let waker_events;
            let notified;
            let mut num_fd_events;
            if self.notify_waker.fd().is_some() {
                waker_events = fds.poll_fds[0].0.revents;
                notified = waker_events != 0;
                num_fd_events = if notified { num_events - 1 } else { num_events }
            } else {
                waker_events = 0;
                notified = self.notify_waker.woken();
                num_fd_events = num_events;
            };

            let pending_wake_token = self.pending_wake_token.lock().unwrap().take();

            if notified {
                self.notify_waker.ack_and_reset();
                if pending_wake_token.is_some() {
                    num_fd_events += 1;
                }
            }

            // We now check whether this poll was performed with descriptors which were pending
            // for removal and filter out any matching.
            let mut pending_removal_guard = self.pending_removal.lock().unwrap();
            let mut pending_removal = std::mem::replace(pending_removal_guard.as_mut(), Vec::new());
            drop(pending_removal_guard);

            // Store the events if there were any.
            if num_fd_events > 0 {
                let fds = &mut *fds;

                events.reserve(num_fd_events);

                // Add synthetic events we picked up from calls to wake()
                if let Some(pending_wake_token) = pending_wake_token {
                    events.push(Event {
                        token: pending_wake_token,
                        events: waker_events,
                    });
                }

                for fd_data in fds.fd_data.values_mut() {
                    let PollFd(poll_fd) = &mut fds.poll_fds[fd_data.poll_fds_index];

                    if pending_removal.contains(&poll_fd.fd) {
                        // Fd was removed while poll was running
                        continue;
                    }

                    if poll_fd.revents != 0 {
                        // Store event
                        events.push(Event {
                            token: fd_data.token,
                            events: poll_fd.revents,
                        });

                        if poll_fd.revents & (libc::POLLHUP | libc::POLLERR) != 0 {
                            pending_removal.push(poll_fd.fd);
                            closed_raw_fds.push(poll_fd.fd);
                        }

                        // Remove the interest which just got triggered the IoSourceState's do_io
                        // wrapper used with this selector will add back the interest using
                        // reregister.
                        poll_fd.events &= !poll_fd.revents;

                        // Minor optimization to potentially avoid looping n times where n is the
                        // number of input fds (i.e. we might loop between m and n times where m is
                        // the number of fds with revents != 0).
                        if events.len() == num_fd_events {
                            break;
                        }
                    }
                }

                break; // No more polling.
            }

            // If we didn't break above it means we got woken up internally (for example for adding an fd), so we poll again.
        }

        drop(fds);
        let _ = self.deregister_all(&closed_raw_fds);

        Ok(())
    }

    pub fn register(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
        self.register_internal(fd, token, interests).map(|_| ())
    }

    pub fn register_internal(
        &self,
        fd: RawFd,
        token: Token,
        interests: Interest,
    ) -> io::Result<Arc<RegistrationRecord>> {
        #[cfg(all(debug_assertions, not(target_os = "wasi")))]
        if Some(fd) == self.notify_waker.fd() {
            return Err(io::Error::from(io::ErrorKind::InvalidInput));
        }

        // We must handle the unlikely case that the following order of operations happens:
        //
        // register(1 as RawFd)
        // deregister(1 as RawFd)
        // register(1 as RawFd)
        // <poll happens>
        //
        // Fd's pending removal only get cleared when poll has been run. It is possible that
        // between registering and deregistering and then _again_ registering the file descriptor
        // poll never gets called, thus the fd stays stuck in the pending removal list.
        //
        // To avoid this scenario we remove an fd from pending removals when registering it.
        let mut pending_removal = self.pending_removal.lock().unwrap();
        if let Some(idx) = pending_removal.iter().position(|&pending| pending == fd) {
            pending_removal.swap_remove(idx);
        }
        drop(pending_removal);

        self.modify_fds(|fds| {
            if fds.fd_data.contains_key(&fd) {
                return Err(io::Error::new(
                    io::ErrorKind::AlreadyExists,
                    "I/O source already registered this `Registry` \
                    (an old file descriptor might have been closed without deregistration)",
                ));
            }

            let poll_fds_index = fds.poll_fds.len();
            let record = Arc::new(RegistrationRecord::new());
            fds.fd_data.insert(
                fd,
                FdData {
                    poll_fds_index,
                    token,
                    shared_record: record.clone(),
                },
            );

            fds.poll_fds.push(PollFd(libc::pollfd {
                fd,
                events: interests_to_poll(interests),
                revents: 0,
            }));

            Ok(record)
        })
    }

    cfg_any_os_ext! {
    pub fn reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
        self.modify_fds(|fds| {
            let data = fds.fd_data.get_mut(&fd).ok_or(io::ErrorKind::NotFound)?;
            data.token = token;
            let poll_fds_index = data.poll_fds_index;
            fds.poll_fds[poll_fds_index].0.events = interests_to_poll(interests);

            Ok(())
        })
    }

    pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
        self.deregister_all(&[fd])
            .map_err(|_| io::ErrorKind::NotFound)?;
        Ok(())
    }
    }

    /// Perform a modification on `fds`, interrupting the current caller of `wait` if it's running.
    fn modify_fds<T>(&self, f: impl FnOnce(&mut Fds) -> T) -> T {
        self.waiting_operations.fetch_add(1, Ordering::SeqCst);

        // Wake up the current caller of `wait` if there is one.
        let sent_notification = self.notify_waker.wake().is_ok();

        let mut fds = self.fds.lock().unwrap();

        // If there was no caller of `wait` our notification was not removed from the pipe.
        if sent_notification {
            self.notify_waker.ack_and_reset();
        }

        let res = f(&mut *fds);

        if self.waiting_operations.fetch_sub(1, Ordering::SeqCst) == 1 {
            self.operations_complete.notify_one();
        }

        res
    }

    /// Special optimized version of [Self::deregister] which handles multiple removals
    /// at once.  Ok result if all removals were performed, Err if any entries
    /// were not found.
    fn deregister_all(&self, targets: &[RawFd]) -> Result<(), ()> {
        if targets.is_empty() {
            return Ok(());
        }

        let mut pending_removal = self.pending_removal.lock().unwrap();
        pending_removal.extend(targets);
        drop(pending_removal);

        self.modify_fds(|fds| {
            let mut all_successful = true;

            for target in targets {
                match fds.fd_data.remove(target).ok_or(()) {
                    Ok(data) => {
                        data.shared_record.mark_unregistered();
                        fds.poll_fds.swap_remove(data.poll_fds_index);
                        if let Some(swapped_pollfd) = fds.poll_fds.get(data.poll_fds_index) {
                            fds.fd_data
                                .get_mut(&swapped_pollfd.0.fd)
                                .unwrap()
                                .poll_fds_index = data.poll_fds_index;
                        }
                    }
                    Err(_) => all_successful = false,
                }
            }

            if all_successful {
                Ok(())
            } else {
                Err(())
            }
        })
    }

    #[cfg(not(target_os = "wasi"))]
    pub fn wake(&self, token: Token) -> io::Result<()> {
        self.pending_wake_token.lock().unwrap().replace(token);
        self.notify_waker.wake()
    }

The poll(2) Selector implementation uses Mutex, Condvar, and AtomicUsize to coordinate between a thread calling select() and threads calling register()/reregister()/deregister(). The modify_fds() method increments waiting_operations, wakes a polling thread via the internal waker, acquires the fds lock, performs the modification, and notifies via operations_complete condvar. The select() loop waits on operations_complete before calling poll(), preventing torn updates. SelectorInner on Windows uses Mutex<VecDeque<...>> for the update queue and AtomicBool (is_polling) to serialize IOCP updates. Arc<Mutex> provides safe shared ownership of socket state between the selector and callbacks. Justifies uses-concurrency, impl-concurrency, concurrency-safe, concurrency-documented, concurrency-impl-safe, concurrency-impl-correct, and concurrency-impl-documented.

src/sys/unix/waker

The Waker is backed by eventfd (Linux/illumos/ESP-IDF), a kqueue EVFILT_USER event (macOS/BSD), or a Unix pipe (other Unix platforms). The eventfd implementation writes a 1u64 value to wake and reads to reset. The pipe implementation writes a single byte and drains the buffer on overflow. The kqueue implementation uses EV_ADD|EV_RECEIPT|NOTE_TRIGGER. All three implementations handle WouldBlock gracefully by draining before retrying. The pipe Waker correctly holds both sender and receiver file descriptors as owned File values ensuring prompt cleanup. Justifies impl-concurrency (Waker is a cross-thread wake primitive) and unsafe-safe for this code path.

src/sys/unix/waker/eventfd.rs

std::fs::File is used as an owning wrapper for raw file descriptors (eventfd fd, pipe fds, Windows AFD handle). In all cases the fd is obtained from a successful syscall and immediately wrapped with File::from_raw_fd/from_raw_handle, ensuring the fd is valid and ownership is correctly established. No filesystem path operations are performed; the File type is used solely as an RAII fd holder and for its Read/Write trait implementations on pipes. Justifies uses-filesystem and filesystem-safe.

src/sys/windows/selector.rs

src/sys/windows/selector.rs, line 190-310

        unsafe {
            self.afd.cancel(&mut *self.iosb)?;
        }
        self.poll_status = SockPollStatus::Cancelled;
        self.pending_evts = 0;
        Ok(())
    }

    // This is the function called from the overlapped using as Arc<Mutex<SockState>>. Watch out for reference counting.
    fn feed_event(&mut self) -> Option<Event> {
        self.poll_status = SockPollStatus::Idle;
        self.pending_evts = 0;

        let mut afd_events = 0;
        // We use the status info in IO_STATUS_BLOCK to determine the socket poll status. It is unsafe to use a pointer of IO_STATUS_BLOCK.
        unsafe {
            if self.delete_pending {
                return None;
            } else if self.iosb.Anonymous.Status == STATUS_CANCELLED {
                /* The poll request was cancelled by CancelIoEx. */
            } else if self.iosb.Anonymous.Status < 0 {
                /* The overlapped request itself failed in an unexpected way. */
                afd_events = afd::POLL_CONNECT_FAIL;
            } else if self.poll_info.number_of_handles < 1 {
                /* This poll operation succeeded but didn't report any socket events. */
            } else if self.poll_info.handles[0].events & afd::POLL_LOCAL_CLOSE != 0 {
                /* The poll operation reported that the socket was closed. */
                self.mark_delete();
                return None;
            } else {
                afd_events = self.poll_info.handles[0].events;
            }
        }

        afd_events &= self.user_evts;

        if afd_events == 0 {
            return None;
        }

        // In mio, we have to simulate Edge-triggered behavior to match API usage.
        // The strategy here is to intercept all read/write from user that could cause WouldBlock usage,
        // then reregister the socket to reset the interests.
        self.user_evts &= !afd_events;

        Some(Event {
            data: self.user_data,
            flags: afd_events,
        })
    }

    pub fn is_pending_deletion(&self) -> bool {
        self.delete_pending
    }

    pub fn mark_delete(&mut self) {
        if !self.delete_pending {
            if let SockPollStatus::Pending = self.poll_status {
                drop(self.cancel());
            }

            self.delete_pending = true;
        }
    }

    fn has_error(&self) -> bool {
        self.error.is_some()
    }
}

cfg_io_source! {
    impl SockState {
        fn new(raw_socket: RawSocket, afd: Arc<Afd>) -> io::Result<SockState> {
            Ok(SockState {
                iosb: IoStatusBlock::zeroed(),
                poll_info: AfdPollInfo::zeroed(),
                afd,
                base_socket: get_base_socket(raw_socket)?,
                user_evts: 0,
                pending_evts: 0,
                user_data: 0,
                poll_status: SockPollStatus::Idle,
                delete_pending: false,
                error: None,
                _pinned: PhantomPinned,
            })
        }

        /// True if need to be added on update queue, false otherwise.
        fn set_event(&mut self, ev: Event) -> bool {
            /* afd::POLL_CONNECT_FAIL and afd::POLL_ABORT are always reported, even when not requested by the caller. */
            let events = ev.flags | afd::POLL_CONNECT_FAIL | afd::POLL_ABORT;

            self.user_evts = events;
            self.user_data = ev.data;

            (events & !self.pending_evts) != 0
        }
    }
}

impl Drop for SockState {
    fn drop(&mut self) {
        self.mark_delete();
    }
}

/// Converts the pointer to a `SockState` into a raw pointer.
/// To revert see `from_overlapped`.
fn into_overlapped(sock_state: Pin<Arc<Mutex<SockState>>>) -> *mut c_void {
    let overlapped_ptr: *const Mutex<SockState> =
        unsafe { Arc::into_raw(Pin::into_inner_unchecked(sock_state)) };
    overlapped_ptr as *mut _
}

/// Convert a raw overlapped pointer into a reference to `SockState`.
/// Reverts `into_overlapped`.
fn from_overlapped(ptr: *mut OVERLAPPED) -> Pin<Arc<Mutex<SockState>>> {
    let sock_ptr: *const Mutex<SockState> = ptr as *const _;
    unsafe { Pin::new_unchecked(Arc::from_raw(sock_ptr)) }
}

Of 114 unsafe blocks in the codebase, only 21 carry a // SAFETY: or // Safety: comment explaining the invariants. The Windows IOCP, AFD, and named pipe paths are the most affected. The undocumented blocks include direct dereferences of OVERLAPPED pointers cast to typed pointers, uses of Pin::into_inner_unchecked and Arc::into_raw/from_raw for lifetime management of SockState, and raw fd wrapping. This pattern establishes that unsafe-documented is false. See FINDING-1.