c++c++14thread-localstatic-initializationdestruction

thread_local static class is destroyed at invalid address on program exit


I have an issue with the destruction of a thread_local static object.

#include <iostream>
#include <thread>

struct UsesLoc {
    UsesLoc() {
        loc.counter++;
    }

    struct Loc {
        Loc() {
            std::cout << "I am at   " << this << " and counter is " << counter << std::endl;
        }
        ~Loc() {
            std::cout << "I was at  " << this << " and counter is " << counter << std::endl;
        }

        int counter = 0;
    };

    static thread_local Loc loc;
};

thread_local UsesLoc::Loc UsesLoc::loc;

int main()
{
    {
        UsesLoc usesloc;
        std::cout << "loc is at " << &UsesLoc::loc << " and counter is " << UsesLoc::loc.counter << std::endl;
    }
    return 0;
}

As expected, compiling and running on https://coliru.stacked-crooked.com/a/e8bcfdaffa6a6da7 reveals that the thread_local object is always at the same location and the counter values are (0,1,1):

I am at   0x7f9dc817673c and counter is 0
loc is at 0x7f9dc817673c and counter is 1
I was at  0x7f9dc817673c and counter is 1

Conversely, when I locally compile with MinGW and run, I get, for instance,

I am at   0x507874 and counter is 0
loc is at 0x507874 and counter is 1
I was at  0x7efdd000 and counter is 2686552

Clearly, an uninitialized object at a different memory location is destroyed.

Did I oversee anything non-deterministic? How can I ensure that the correct object is destroyed?


Solution

  • After getting a hint from Ted Lyngmo that this might be a compiler bug, I did a bit of research and it seems to be indeed an issue already reported before:

    That being said, the code is correct and the pointer to the object being destructed points to the same object that was constructed before when using a standard-compliant compiler.