C++ Logo

std-proposals

Advanced search

Re: Make side effects in static initialization more consistent

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Mon, 21 Dec 2020 13:08:41 +0000
According to cppreference.com under deffered dynamic initialization:

> If no variable or function is odr-used from a given translation unit,
> the non-local variables defined in that translation unit may never be
> initialized (this models the behavior of an on-demand dynamic
> library).

https://en.cppreference.com/w/cpp/language/initialization#Deferred_dynamic_initialization

After a quick search I didn't find normative wording that allows
eliding initialization of variables that have deferred dynamic
initialization. But:

* For better or worse this seems to be implementation practice since a
  long time, notable examples are deferred loading of a dynamic library
  on Windows and lazy static linking on Linux.

* Even if initialization were guaranteed to happen it could be too late
  for registration purposes.

I see merit in the proposal, but maybe there
are implementation challenges. It's probably solvable for static
linking, but on-demand dynamic loading could be inherent how dynamic
libraries work on Windows (I'm not familiar).

Regards,
Lénárd Szolnoki

On Mon, 21 Dec 2020 13:12:08 +0100
Marcin Jaczewski via Std-Proposals <std-proposals_at_[hidden]>
wrote:

> Isn't this break of As-If rule? Linker can remove variables only if
> you cannot detect that.
> If constructor/initialization did some not trivial thing then you can
> clearly see the difference if it was run or not.
> Variable itself could disappear but side effects should stay.
>
> It is possible that there is some clause in the standard that allows
> this but if we fix it we should alter it not adding new things.
>
> pon., 21 gru 2020 o 12:06 kh via Std-Proposals
> <std-proposals_at_[hidden]> napisał(a):
> >
> > Initialization of variables might carry side effects. The behavior
> > for these effects is usually well-defined. One exception is the
> > initialization of global variables with static storage duration.
> >
> > The main problem is that the linker could remove unused variables.
> > The linker then also eliminates any side effects of the
> > initialization. This might cause problems in some cases when the
> > side effect is expected. The problem is strongly related to static
> > linking. I couldn't observe it when linking the object files
> > directly into an executable or in a shared library. This
> > inconsistency is also problematic.
> >
> > Example 1: The side effect is used to register an algorithm by name
> > that can be created without knowing the concrete type later ("self
> > registering factory").
> > https://godbolt.org/z/YTqEW7
> >
> > Example 2: Many C-Libraries need an explicit call to an init
> > function before the library is usable. A common solution is to do
> > this statically at one place, so it can't be forgotten.
> >
> > Alternatives to get the above example working with static linking:
> > - Explicitly do the registration and do not rely on static
> > initialization side effects.
> > - Write this code by hand.
> > - Perform a mock step to generate the registration code.
> > - Use platform dependent linker flags to completely disable removal
> > of unused symbols.
> > - Trick the optimizer to include the unused symbols (Hacks):
> > - Add unnecessary includes.
> > - Place the initialization statement inside a header file.
> > - Dummy access to static variables so the linker is not allowed
> > to remove them.
> > - Bugusing
> >
> > Possible solutions to guarantee code execution before entering
> > main():
> > - Add an attribute for (static) variables that should not be
> > discarded by the linker. e.g. [[nodiscard]] or [[keep]]
> > - No impact on existing code as it adds a new attribute that is
> > optional. It also does not alter the default behavior.
> > [[keep]] const auto MyUnusedVariable = InitializeSomeLibrary(); //
> > This happens in global scope.
> >
> > - prevent the linker from removing static variables which have an
> > initializer with a side effect.
> > - Might be impossible to detect.
> > - Could have a performance impact on existing codebases.
> >
> > - add a general construct to execute code before entering main(), so
> > the user is no longer required to fake initialize with dummy
> > variables and side effects.
> > - Syntactic sugar for the lambda initializer combined with an
> > execution guarantee.
> > - The problem still exists. There is just another syntax to
> > circumnavigate it.
> > initialize
> > {
> > const auto MyUnusedVariable = InitializeSomeLibrary();
> > }
> >
> > It might also be a good idea to warn when the linker throws away
> > symbols with side effects (Which might be impossible to detect in
> > some cases).
> >
> > Regards,
> > Konstantin Harmuth
> > --
> > Std-Proposals mailing list
> > Std-Proposals_at_[hidden]
> > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2020-12-21 07:08:48