Change:
} #[inline(always)] <del> pub unsafe fn init(_argc: isize, _argv: *const *const u8) { // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize // `ARGC` and `ARGV`. But in Miri that does not actually happen so we // still initialize here. #[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))] really_init(_argc, _argv); </del> <ins> pub unsafe fn init(argc: isize, argv: *const *const u8) { // on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work" // BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc. really_init(argc, argv); </ins> } /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.

Discussion:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code in Alpine Linux cross compiled to : For reference I ran this in a container on an M1 Macbook: I always see printed, even when I pass the program arguments. I'm not sure this is an issue with the environment as the following C program works as expected: :
uh.
Could you clarify: Does this problem arise with code ran on an ordinary gnu system? Say, a Debian container? Or itself?
I can take a guess at why this happens. For glibc targets we assume that the arguments can be retrieved without needing to store and . However if this musl compatibility layer doesn't use the then we can't retrieve them.
Ah yeah, it seems that behavior is a GNU extension that Rich Felker doesn't want to support?
Does just not work at all on musl if we're a cdylib, then?
Correct. When libstd's start function isn't used, only works on Windows, macOS and Linux with Glibc. On any other target it returns an empty list.
Apparently we already have this comment: In other words, we are already hacking around this issue for the miri emulator, and not using the fact that we are still given argv "naturally" via execve. We should probably just unconditionally call .
That would fix on Linux + glibc too.
Note that this was intentionally done but there have been other issues
I still think we can consider to still be fixed, as we just get our and it will be the same thing, even if the s behind the have been rearranged, right? So we'll set the atomics twice to the same value, which sounds very Working As Intended.
— in Well, given the remarks here seem to position this as a "wouldn't it be nice if we didn't do extra work?" and that this seems to be non-resilient in practice, as it has caused more than one open issue, I think we should be unafraid of doing a bit of extra computation.
I more meant that the fact that libraries mess about with (what should be) immutable memory is a safety issue so ideally we would parse it at the point where it's least likely that the are multiple threads.

But people would probably complain about doing unnecessary allocating and extra work pre-main. Just storing argc and argv should be cheap though so I'm definitely not arguing against that.
the dilemma: strictly conforming posix programs shouldn't mutate argc and argv, but strictly conforming posix programs also shouldn't be aware of argc and argv if if they're dylibs, eh?
Could we check, first, whether we've already had these initialized, and only call this in the unusual case where they're not initialized? That would avoid the extra work in the common case, and do the work in the unusual case.
I don't know what you mean? We aren't doing substantial extra work. The thing that costs the most in runtime startup, I expect, is having the static initializer at all, which we then don't get to make choices about whether its called. It simply is or isn't.
Nevermind: ; forgot that was just saving off the values and not doing anything with them.