-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
There was a good question raised in the user forum. The libc
crate defines structs with fields for NUL
-terminated strings as [c_char; N]
, e.g. in ifreq
:
libc/src/unix/linux_like/linux/mod.rs
Line 1529 in c1d2b8e
pub ifr_name: [c_char; crate::IFNAMSIZ], |
The problem is that Rust requires arrays to have all elements initialized, but C typically doesn't care whether the bytes after NUL
are initialized or not. The C and Rust definition of such structs is not exactly equivalent, since the C side could have uninitialized bytes after the NUL
terminator.
I don't expect it this to cause problems in practice, but I can imagine a scenario where this could be UB in theory. Even if the Rust side initializes the struct before a system libc call:
let mut tmp: libc::ifreq = mem::zeroed();
ioctl(&mut tmp);
println!("{tmp:?}");
The libc implementation could end up de-initializing the bytes after NUL
by copying the whole struct from somewhere else that hasn't been fully initialized:
void ioctl(struct ifreq *out) {
memcpy(out, some_partially_initialized_template, sizeof(struct ifreq));
}
C doesn't seem to guarantee that bytes past NUL
are initialized, but also doesn't promise it won't touch them.
Maybe the libc
crate should have a type more suited to express that?[MaybeUninit<c_char>; N]
, or perhaps ArrayCString<N>
that wraps MaybeUninit
bytes and acts like a CStr
?