On Tuesday, 8 January 2019 at 12:54:11 UTC, RazvanN wrote:
Hi all,
I am working on issue 14650 [1]
Great!
(I am _extremely_ surprised that dtors are not called for
globals.)
and I would like to implement a
solution where static destructors are destroying global
variables. However, I have the following problem in
druntime/src/rt/sections_elf_shared:
struct ThreadDSO
{
DSO* _pdso;
static if (_pdso.sizeof == 8) uint _refCnt, _addCnt;
else static if (_pdso.sizeof == 4) ushort _refCnt, _addCnt;
else static assert(0, "unimplemented");
void[] _tlsRange;
alias _pdso this;
// update the _tlsRange for the executing thread
void updateTLSRange() nothrow @nogc
{
_tlsRange = _pdso.tlsRange();
}
}
Array!(ThreadDSO) _loadedDSOs;
For this code, I would have to create the following static
destructor:
static ~this() { _loadedDSOs.__dtor(); }
Because Array defines a destructor which sets its length to 0.
However this code leads to segfault when compiling any program
with the runtime (betterC code compiles successfully). In my
attempt to debug it, I dropped my patch and added the above
mentioned static destructor manually in druntime which lead to
the same effect. Interestingly, _loadedDSOs.__dtor runs
successfully, the segmentation fault comes from somewhere
higher in the call path (outside of the _d_run_main function
(in rt/dmain2.d)). I'm thinking that the static destructor
somehow screws up the object which is later referenced after
the main program finished executing. Does someone well versed
in druntime has any ideas what's happening?
This is my guess:
Have a look at `_d_dso_registry` and it's description. The
function is also called upon shutdown and it accesses
`_loadedDSOs`.
As part of shutdown, `_d_dso_registry` calls
`runModuleDestructors` (which will run your compiler-inserted
static dtor), but _after_ that `_d_dso_registry` accesses
`_loadedDSOs`. I don't know exactly why the segfault happens, but
the code assumes in several places that `_loadedDSOs` is
non-empty. For example, `popBack` is called and `popBack` is
invalid for length=0 (it will set the length to `size_t.max` !).
I think the solution is to not have `_loadedDSOs` be of type
`Array!T` but of a special type that explicitly has no dtor (i.e.
the "dtor" should only be called explicitly such that the data
needed for shutdown survives `runModuleDestructors`). This
probably applies to more of these druntime low-level arrays and
other data structures.
-Johan
[1] The dtor of Array calls reset, and reset has a bug in
rt.util.container.Array. Note the invariant: `assert(!_ptr ==
!_length);`, which triggers when `_length` is set to 0, but
`_ptr` is not set to `null`. !!!