Ask questionsStdlib contains a static initializer on Linux, without any way to opt out
The Rust stdlib has a single static initializer on the cfg #[cfg(all(target_os = "linux", target_env = "gnu"))]
.
In general the stdlib is already avoiding static initializers, and this one is added to support interaction with glibc from inside a cdylib. Typically, args::init() is called during startup which initializes the std::env::args() data structures. But in a cdylib, there’s no startup call that gets through, whereas glibc will call the function pointer in this static initializer.
We would like to provide a mechanism to remove this static initializer, and accept that std::env::args() will be empty as a result inside a cdylib. Since Chromium (as in chrome.exe) does not use argument parsing in Rust, we are fine with the result being, and prefer, that the argument/environment are empty on Linux with glibc with the static initializer being removed if we have Rust code in a cdylib.
While this particular static initializer is not hugely problematic, it is a much better engineering position to work from if there are none at all.
Chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1445935
Static initialization is known to be a problem, due to the Static Initialization Order Fiasco. They also have a measurable negative impact on startup speed, even on modern computers. The Chromium project bans static initializers to avoid these problems.
Many software shops try to avoid static initializers. The Google C++ Style guide tries to ban them but hedges a little.
LLVM provides link-time mechanisms to override a symbol and remove static initializers, such as with __llvm_pgo_register_write_atexit()
in compiler-rt.
We propose to add a feature explicit-init-args-with-glibc
which defaults off, and gate the static initializer’s presence on this feature.
As well, when the feature is enabled, allow the args::imp::init()
function to call really_init() directly. Basically, this feature disables the “linux + gnu” cfg check.
When this feature is enabled and the stdlib is linked statically into a Rust executable or Rust dylib, the init() path will be properly called, explicitly.
When statically linked into a C executable or a C shared-library, the init() path is already not called. When the feature is enabled, it will also not be called in Rust cdylibs, and the std::env::args()
will not be available.
A colleague suggested we could change the cfg guard in sys/unix/args.rs to be a single check like #[cfg(use-glibc-static-initializer)]
and then have the build.rs
file add that cfg flag when on Linux/GNU and the explicit-init-args-with-glibc
feature is not enabled. This moves the combination of these things to a single place in build.rs
at the cost of adding a layer of abstraction.
PR is here: https://github.com/rust-lang/rust/pull/111920
Answer
questions
the8472
Static initialization is known to be a problem, due to the Static Initialization Order Fiasco. They also have a measurable negative impact on startup speed, even on modern computers.
Since this is the underlying motivation: If these ever become a problem I think PRs that fix ordering issues or optimize performance of expensive initializers without removing them entirely also have a better chance of being accepted than #[cfg]
s.
Related questions
No questions were found.