pub struct NetHandle { /* private fields */ }Expand description
Opaque handle to an event bus instance.
This wraps the EventBus along with a Tokio runtime for async operations.
§Lifetime / soundness
The handle storage is intentionally leaked on net_shutdown rather
than freed via Box::from_raw. Reasoning: every FFI entry point
dereferences the C-side *mut NetHandle to access the atomics that
gate shutdown. The previous Dekker-style SeqCst handshake between
FfiOpGuard::try_enter (which calls fetch_add on active_ops) and
net_shutdown (which loads active_ops then Box::from_raws the
handle) was unsound: SeqCst orders the atomic operations only — the
non-atomic Box::from_raw could deallocate the storage between
shutdown’s load and a concurrent FFI op’s fetch_add, producing a
use-after-free on the freed atomic. By never freeing the box, the
atomic memory backing the handle is always valid; concurrent FFI ops
observe shutting_down=true after shutdown signals it and bail
before touching bus/runtime.
bus and runtime are stored in ManuallyDrop so that
net_shutdown can take them out (via ptr::read) in order to
call bus.shutdown().await. Because shutting_down is set first
and shutdown waits for active_ops to drop to zero before reading
these fields, no FFI op can be racing the read. If the wait times
out, the ptr::read is skipped and both fields are leaked along
with the box.