Code change:
// list. let argv = ARGV.load(Ordering::Relaxed); let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) }; <del> (0..argc) .map(|i| { let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char); OsStringExt::from_vec(cstr.to_bytes().to_vec()) }) .collect() </del> <ins> let mut args = Vec::with_capacity(argc as usize); for i in 0..argc { let ptr = *argv.offset(i) as *const libc::c_char; // Some C commandline parsers (e.g. GLib and Qt) are replacing already // handled arguments in `argv` with `NULL` and move them to the end. That // means that `argc` might be bigger than the actual number of non-`NULL` // pointers in `argv` at this point. // // To handle this we simply stop iterating at the first `NULL` argument. // // `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments // after the first `NULL` can safely be ignored. if ptr.is_null() { break; } let cstr = CStr::from_ptr(ptr); args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec())); } args </ins> } } }

Related discussion:
text: However, just like multi-threaded programs cannot mutate the process environment or write to the global pointer ( is inherently unsafe if there are other threads; also see the discussion in ), I would argue that multi-threaded programs cannot mutate . Global state such as or is inherently read-only in a concurrent program; there is just no way to make mutation safe. So, I think for concurrent programs we can already assume that there are no concurrent mutations, and if there are then that is a bug in the code that performs the mutation. What remains is the question whether we should adjust the args handling to be able to deal with NULL pointers in .
The problem here is that this behaviour of GLib exists since literally decades, and I'm sure we'll find other commandline parsers that are doing similar things if we search a bit. My first reaction also was that this feels like something to fix in GLib, but that doesn't seem to be a practical resolution because of the above. Skipping over s seems to be a relatively cheap mitigation if we decide that concurrent modifications of are simply wrong (who even does that! also seems less likely than ).
I can't judge how common it is to add NULLs there, and don't have an opinion on whether we should support that -- let's see what says. If you know of another library doing this that could be useful, though GLib doing it for decades on its own already means this is quite wide-spread. I hope GLib does this before any threads are spawned, because otherwise I'm afraid that is just inherently doomed.
I'll search a bit later. An application could surely do that, but that's just asking for problems and I wouldn't really worry about that. The following would work around this FWIW. Maybe should be conditional on glibc.
nit: s/Same/Some
Qt does the same thing in in . It shuffles around arguments in and removes (by setting to ) arguments it handled already.
's library is not affected because it always copies each string directly into a vector and then operates on that.
Another approach would be parsing . Doesn't work if proc isn't available, but so do things like .
is created by the kernel reading from the original location of argv (as specified by the auxiliary vector). If you edit argv, so will the commandline reported by the kernel.