No sound way to zero-copy from socketaddr_in
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 870
- Forks
- 305
- PR merge metrics
- No merged PRs in 30d
Description
This is most painful on Windows, where SOCKADDR_STORAGE is 132 bytes long.
Consider the following naive example code, where the SOCKADDR pointer here is a pointer to an ipv4/ipv6 address obtained via syscall:
unsafe fn sock_addr_to_ip(ptr: *const SOCKADDR, length: i32) -> Option<IpAddr> {
let sa = socket2::SockAddr::new(*(ptr as *const SOCKADDR_STORAGE), length);
sa.as_socket().map(|s| s.ip())
}
The issue is that SOCKADDR_STORAGE is larger than SOCKADDR, the pointer is only guaranteed to be valid through length bytes, and so casting it to *const SOCKADDR_STORAGE and dereferencing immediately introduces UB.
The correct code looks more like this:
unsafe fn sock_addr_to_ip(ptr: *const SOCKADDR, length: i32) -> Option<IpAddr> {
assert!(length as usize <= std::mem::size_of::<SOCKADDR_STORAGE>());
let mut storage = std::mem::MaybeUninit::<SOCKADDR_STORAGE>::uninit();
std::ptr::copy_nonoverlapping(ptr, &mut storage as *mut _ as *mut _, length as _);
let sa = socket2::SockAddr::new(storage.assume_init(), length);
sa.as_socket().map(|s| s.ip())
}
Since the backing storage for SockAddr is owning, we have to make a copy. It's incredibly awkward and a bit slower. And that's just so we can safely invoke the nice parsing logic in as_socket().
To fix this we'd probably have to add a SockAddrRef<'a> type that doesn't own its backing storage. If that's not immediately feasible, providing a constructor that performs this unsafe copy inside socket2 would also solve the immediate issue.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing socket2::SockAddr and its as_socket() parsing path, using the issue's SOCKADDR and SOCKADDR_STORAGE examples as the safety boundary. Compare the proposed borrowed SockAddrRef approach with a constructor that performs the copy, and define completion as safe handling of pointers valid only for the supplied length without requiring callers to copy into SOCKADDR_STORAGE.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- networking
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100