Skip to content

Reconsider magic static usage, as there should be no portability issues since XP dropping #673

@AlexGuteniev

Description

@AlexGuteniev

I'm referring to this #448 (comment)

Adding a .TLS section to a DLL that previously didn't have one can push a program over the TLS slot limit, so it's a breaking change.

My understanding is the limit in Vista was changed from ~58 to ~1000ish but that there is still a limit.

I think that TLS algorithm starting from Vista allows virtually infinite TLS slots (that is limited only by virtual address space).

I think the algorithm abandons old TLS tables without deallocating them. They are deallocated on thread exit. TLS slot table just grows, but with ability of slot reuse. Something like this.

I'm not sure if it is true for Vista, but at least for Windows 10 it seems to work.

I can show, please follow me:


d:\Temp>type myshka.cpp
thread_local int i = 0;

extern "C" __declspec(dllexport) int* GetTlsVar()
{
    i += 1;
    return &i;
}

d:\Temp>type koshka.cpp
#include <Windows.h>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <unordered_set>

int main()
{
    std::vector<HMODULE> dlls;
    for (int i = 0; i < 30'000; i++)
    {
         std::ostringstream name;
         std::ostringstream cmd;
         name << "myshka_" << i <<".dll";
         if (!::CopyFileA("myshka.dll", name.str().c_str(), FALSE))
         {
             std::cerr << "can't copy\n";
             return 2;
         }
         HMODULE m = ::LoadLibraryA(name.str().c_str());
         if (m == NULL)
         {
             std::cerr << "can't load\n";
             return 3;
         }
         dlls.push_back(m);
    }
    std::cout << "dlls loaded\n";
    for (int expectation : {1, 2})
    {
        std::unordered_set<int*> uniq;
        for (HMODULE m : dlls)
        {
            auto TlsVarFcnPtr = reinterpret_cast<int*(*)()>(::GetProcAddress(m, "GetTlsVar"));
            auto TlsVarPtr = TlsVarFcnPtr();
            if (TlsVarPtr == NULL)
            {
                std::cerr << "can't indirect\n";
                return 4;
            }
            auto TlsVarVal = *TlsVarPtr;
            if (TlsVarVal != expectation || uniq.count(TlsVarPtr) != 0)
            {
               std::cerr << "Bad TLS data " << TlsVarPtr << '\t' << TlsVarVal << '\n';
               return 5;
            }
            uniq.insert(TlsVarPtr);
       }
    }
    std::cout << "all fine\n";
    return 0;
}


d:\Temp>"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64

d:\Temp>cl /MD /EHsc myshka.cpp /link /DLL /out:myshka.dll
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

myshka.cpp
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:myshka.exe
/DLL
/out:myshka.dll
myshka.obj
   Creating library myshka.lib and object myshka.exp

d:\Temp>cl /MD /EHsc koshka.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

koshka.cpp
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:koshka.exe
koshka.obj

d:\Temp>koshka
dlls loaded
all fine

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementSomething can be improvedwontfixThis will not be worked on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions