rust-lang / rust-lang/libc

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

Open
#4,456 10 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
2.6k
Forks
1.3k
Avg merge
1d 22h
Merged PRs (30d)
69

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:

https://github.com/rust-lang/libc/blob/c1d2b8e055e29b239a308f10b38a6b6138711612/src/unix/linux_like/linux/mod.rs#L1529

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?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the ifreq definition in src/unix/linux_like/linux/mod.rs at the referenced location, then read the linked Rust forum discussion about uninitialized data from external functions. Determine whether the current [c_char; N] representation is sound and what replacement, if any, the libc API should adopt; the issue does not define a settled implementation or test target.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
operating-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.