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: Currently in , Rust is hooking into the glibc extension for retrieving / even in case Rust does not manage and is e.g. just loaded into a process as a . While this is great and convenient, it's unfortunately not implemented in a safe way. Various C commandline argument parsers are modifying while parsing, so the information that gets passed into might not be correct anymore. Examples of such parsers are glibc's own  parser, noting " The default is to permute the contents of argv while scanning it so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. " GLib's  parser, which removes all already handled arguments from and only leaves others (removed ones are set to and moved to the end). Qt does the same thing in in . It shuffles around arguments in and removes (by setting to ) arguments it handled already. This means that at least can easily be too big, and Rust would read beyond the (new) end of . This caused crashes in because of calling on when creating an around such an "removed" argument. Now the question is how this should be handled in Rust. I see three options here Remove the extension usage and handle glibc like all other libcs Copy all arguments in . This means everybody has to pay for that even if they don't use arguments, and this is theoretically still not safe if the shared library is loaded at the same time the array is modified and a partially written pointer value is read Handle pointers in by skipping over them. This means we would lose the exact length information of the iterator, and this is still theoretically not safe for the same reason as 2. See This code was in 2019 by (CC I've created as a proposed fix for this, which implements option 3. : <details<summaryBacktrace</summary<pAlso </p</details
Arguably swapping two entries of is still a lot less dangerous than setting one to NULL -- it seems totally legitimate to assume that there are no NULL pointers in , and does not insert any NULL there either. So what GLib does here is certainly questionable, more so than what does. That would be a data race.