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`. !!!

Reply via email to