Currently it is defined as u32 in wasmtime: https://github.com/bytecodealliance/wasmtime/blob/v9.0.0/crates/wasi-common/src/table.rs#L16, but in wasi, the raw fd is i32 https://github.com/rust-lang/rust/blob/master/library/std/src/os/wasi/io/raw.rs#L20. I wonder if there's a reason behind this mismatch, and should we lean to one instead of having both? Thanks.
On the Wasm side of things, u32 makes slightly more sense because it's an index into a table, it's never negative, and in theory there's no fundamental problem with having 1<<31 handles live at a time.
On the C ABI side of things, i32 makes slightly more sense because it's the type that corresponds to the C int type, which is what Unix uses for file descriptors, and thus what a lot of existing code is expecting.
Rust's std::os::wasi follows the C ABI side of things, because existing Rust code may be similarly expecting it to be i32.
In fact, I think on the Rust side RawFd used to be u32, but we changed it to i32 for better compatibility.
It doesn't look good to cast u32 to i32 from host calls, but using a negative fd in wasi should "just work" I guess, unless some lib has the assumption you mentioned. I guess the only issue is, without multiple return value(well, having std recompiled is not always an option), it's going to be tricky for host functions to return a fd or an err.
WASI interfaces have never used -1 to indicate an invalid file descriptor. In Preview1 witx they use (result $error (expected $fd (error $errno))) which lowers to a __wasi_fd_t *retptr0 outparam.
In Preview2, they use a result as well.
Last updated: Dec 06 2025 at 06:05 UTC