Change:
Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool miri has failing tests. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great! cc the PR reviewer, and nominating for compiler team prioritization.
This test is failing:
might give a hint what needs to be updated. I haven't gotten a chance to look closely yet.
Yeah, we'll need to emulate that new static thing by Unfortunately I don't entirely understand the static magic that goes on there... there's just a fn ptr stored in a particular section and somehow that is enough?!?
Yes, all platforms have sections that they treat as an array of pointers, filling the entire section, which makes it easy to append more entries, as linkers will happily concatenate sections with the same name. This is how C++ global constructors are implemented everywhere. So I guess there's two levels to this: miri should collect the platform-specific global ctors/dtors (on Linux I think there's also init/fini which work similarly) and execute them before C main (and after, in the case of dtors) when is , the ctors (or just the init flavor?) can also take 1, 2 or 3 arguments, not only 0 arguments (I believe this is also how C main technically works)
Okay. This is basically I hoped we'd never have to do this... For dtors, we already run TLS dtors, but those are entirely separate (we hook the pthread calls where dtors are set, and then run those functions later). There's no way those can be unified to one mechanism, is there? Also, this begs the question in which order stuff is called before/after main.
C++ asks itself the same question and I personally haven't heard of there being an answer. The safe thing to do is to make sure any order is safe (in Rust you have to initialize global state before any runtime initialization, so it's safer than C++ where before the constructor runs, the fields are uninitialized). The implementations just go through the sections in order, so the unknown quantity is what order the linker concatenates all of these sections. In miri you don't have the linker to think about, but you do need a mechanisms to access all statics from all crates.
Wait, why can't libstd initialize the args from the start lang item as well? Surely there's an inexpensive way to do so?
That's what I did originally, but said not to.
Reverting should fix this.
We could either adjust the 's to no use the new method when is set, or we could implement those initializers. Seems like we'll want them eventually anyway... What would be the best way to do that?
In the short term, excluding from the new mechanism seems like a reasonable solution to unbreak miri. That depends on two factors: what order functions get placed into the sections, and what order they get called. The default linker scripts will collect all sections in sorted order, followed by the section itself, into a single section. Likewise for and . The sort order here uses the linker's , which takes a numeric section suffix as a numeric priority, and sorts sections with non-numeric suffixes asciibetically. (There are also a couple of special cases to make sure that glibc can guarantee its own functions run first/last in a couple of those. And there are some very careful special cases to handle the old , , , and sections, which get translated into corresponding , , , and sections respectively in the final binary to preserve the behavior of those sections, keeping in mind that ctors sections get run in reverse order and the dtors sections get run in forwards order. translates the priority in numbered ctors and dtors sections by subtracting it from .) When loading a program or library, glibc calls the function pointers in in order, then the (single) function (which executes the contents of the section), then the function pointers in in order. At shutdown, glibc calls the function pointers in in reverse order, then the (single) function (which executes the contents of the section). Does that help?
It is a great reference, thanks! So far I have no idea how to wire up all these sections in Miri, but I guess we'll see about that. ;) On a separate note, also broke Miri by removing the getter from . I am not sure yet if there is a replacement that we can use instead. Leaving that here just so that I hopefully can find it later.
I don't see any way to actually do that.
I would prefer to avoid duplicate initialization of arguments. I'd like to make Rust executables smaller, not larger.
I agree, I would accept this change.
I opened a PR for that:
Done. I set it to close this issue since we already have to track the more elaborate approach.
Well, actually closing the issue will require also bumping the submodule to include
I don't understand, this would only be a few bytes with ? To unbreak miri it's probably fine but I'm increasingly worried about , as it allows divergence to exist in ways which are not controlled within miri itself.
I was talking about a user of these facilities, not miri implementation. To expand a bit (although it's kind of offtopic): Rust forces you to mutate a that started out with a constant value (e.g. ), which means nothing else would observe an uninitialized value, just the initial constant value, if it happened to ran before the runtime initialization (which would e.g. replace the with a ). This makes Rust + safer in general than C++ with global constructors.
Ack.
Aand now we also need to wait for to land. That's the third independent Miri-breaking PR in 24h, impressive. ;)

Discussion:
#[inline(always)] pub unsafe fn init(_argc: isize, _argv: *const *const u8) { <del> #[cfg(not(all(target_os = "linux", target_env = "gnu")))] </del> <ins> // 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")) ))] </ins> really_init(_argc, _argv); }