$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] Boost.Build check to see if cxxflags flag is supported?
From: Alexander Grund (alexander.grund_at_[hidden])
Date: 2018-11-09 08:08:42
Am 09.11.18 um 06:50 schrieb degski via Boost:
> I would like to
> request for someone involved in that discussion to write a tl;dr of that
> discussion, as it seems to touch upon a number of issues that are poorly
> understood [also by long-time cpp-war-heroes] in general. /r/cpp might also
> be a good place for this and [comments] could shed more light on this.
As the original author of the PR(s) I'll do this. Note that everything 
below is already explained in detail in the description of the PRs and 
initial issue:
- https://github.com/boostorg/serialization/pull/111, 
https://github.com/boostorg/serialization/pull/128, 
https://github.com/boostorg/serialization/pull/129, 
https://github.com/boostorg/serialization/pull/131 
https://github.com/boostorg/serialization/issues/105
There is also my question on SO: 
https://stackoverflow.com/questions/50064617/order-of-destruction-for-static-function-members-in-shared-libraries
To summarize:
There are 2 issues:
1. Wrong destruction order in shared libraries
2. Bug in Boost.Serialization (`singleton::is_destroyed`)
on 1.: As per the C++ standard the destructors are called in reverse 
order of how the constructors finished. This is even true for static 
initialization (pre-main) and destruction (post-main) of global static 
instances which we have here.
This means if type `Foo` accesses a type `Registry` in its constructor 
it is guaranteed that `Registry` will be constructed before `Foo` and 
destroyed after.
Boost.Serialization makes use of this fact and lets `Foo` register 
itself in `Registry` in the ctor of `Foo` and unregister in the 
destructor of `Foo`.
Now there is the case of shared libraries (see also 
https://github.com/boostorg/serialization/pull/131#discussion_r231498983):
Assume 2 shared libraries build against static Boost, so each of them 
has separate instances of `Registry`, which is also ok.
Now lib1 uses a type `Foo` which gets registered in lib1-`Registry` and 
lib2 uses a type `Bar` which gets registered in lib2-`Registry`. During 
unload/destruction `Foo` is destroyed first as before and 
lib1-`Registry` afterwards. But because shared library behaviour is 
implementation defined we now run into the following situation on Linux 
(not on OSX or Windows): With the destruction of lib1-`Registry` the 
runtime also destroys lib2-`Registry`, probably because they are of the 
same type. One can only guess what happens behind the scenes, but maybe 
a name-map is used or so.
The problem: Now lib2-`Registry` is destroyed before `Bar` and when that 
accesses the `Registry` you get a use-after-free situation and a corruption.
This can be handled (and was pre Boost 1.65) by a flag `is_destroyed` 
which gets set once the singleton destructor is called and checked in 
the destructors accessing another singleton. (Basically: 
`if(!Registry::is_destroyed()) Registry::unregister(this)`)
but here issue 2 (introduced in 1.65):
The singleton template can be used directly by **not** inheriting from 
it. In this case an instance of `T` is returned directly: 
https://github.com/boostorg/serialization/blob/boost-1.68.0/include/boost/serialization/singleton.hpp#L122
BUT: The `is_destroyed` flag is set in the destructor of the singleton 
template: 
https://github.com/boostorg/serialization/blob/boost-1.68.0/include/boost/serialization/singleton.hpp#L157
As `T` is not inherited from `singleton<T>` this destructor 
`~singleton<T>` is never called (because it is never constructed either) 
and hence the flag is never set. See 
https://github.com/boostorg/serialization/pull/131#discussion_r232088304
This is different when `T` is inherited from `singleton<T>` in which 
case the construction of `T` will lead to the construction of 
`singleton<T>` and also destruction which is why **in this case** 
`is_destroyed` works correctly.
Due to this the issue 1. does not get caught and leads to the crash.
The question on this thread was now on how to include the "crash test" 
into BJam:
- We need to build 2 shared libraries
- Link them into static boost
As Boost is build statically BJam does not add `-fPIC` to its compile 
flags but as it is linked into shared libraries later this fails as 
addresses are fixed already. Although BJam has the information (link 
boost library into a shared library) it does not "backpropagate" this 
into the build of boost. See 
https://github.com/boostorg/serialization/pull/131#discussion_r231964634, 
https://github.com/boostorg/serialization/pull/131#issuecomment-437236135
Thanks to Peter Dimovs help we got Robert convinced to include my fix 
into the develop branch of Boost.Serialization: 
https://github.com/boostorg/serialization/commit/f297d80d6ef55ac66525320d0477c17806aa57cd. 
I now hope the tests get included to so it doesn't break in the future.