profile
viewpoint

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 Initializers are a problem

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.

Removing the Static Initializer

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.

Alternatives

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.

Proposed Change

PR is here: https://github.com/rust-lang/rust/pull/111920

rust-lang/rust

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.

useful!

Related questions

No questions were found.
source:https://uonfu.com/
Github User Rank List