Skip to content

Is it sound for fixed-length arrays with NUL-terminated strings to be [c_char; N]? #4456

@kornelski

Description

@kornelski

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:

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions