In short, Stack overflow when VLD gets TLS slot >= 64 and allocate memory in new thread.
On Windows, by default Thread Local Storage (TLS) has 0x40 slots. Later it is expanded by 0x400 more slots. These expansion slots are created on demand when TLS APIs TlsAlloc/TlsFree/TlsGetValue/TlsSetValue are invoked in current thread. And the expansion is achieved by calling Windows API RtlAllocateHeap. When TLS APIs are invoked the first time with slot number >= 0x40 in a thread which hasn't expand before, TLS expansion will be triggered.
To assist troubleshooting memory leak issues, memory allocation APIs, including `RtlAllocateHeap`, are hooked by VLD.
When a memory allocation happens, VLD will store the information in its TLS slot to avoid contention and reduce performance impact. When VLD is assigned with a TLS slot >= 0x40 and a memory allocation happens in a thread that hasn't expand TLS, the access to TLS slot from VLD will trigger another TLS expansion.
However, the expansion will call `RtlAllocateHeap` to allocate memory and the record of this memory allocation will be saved into TLS slot by VLD, which will again trigger another TLS expansion... In this way, The program will enter infinite recursion.
The call stack of this crash will be looks like:
```
6dc9 0759f314 09ddbfcc 00000042 0a16b870 09defbd0 KERNELBASE!TlsSetValue+0x4f
6dca 0759f360 09ddc1a3 09defbd0 00490000 0759f38c vld!VisualLeakDetector::getTls+0xfc [c:\build\vld\v24c\src\vld.cpp @ 1075]
6dcb 0759f370 09dda74b 0baa5930 00000008 0759f69c vld!VisualLeakDetector::enabled+0x23 [c:\build\vld\v24c\src\vld.cpp @ 982]
6dcc 0759f38c 75c445cf 00490000 00000008 00001000 vld!VisualLeakDetector::_HeapAlloc+0x2b [c:\build\vld\v24c\src\vld_hooks.cpp @ 1617]
6dcd 0759f3a8 09ddbfcc 00000042 0a16b870 09defbd0 KERNELBASE!TlsSetValue+0x4f
6dce 0759f3f4 09ddc1a3 09defbd0 05480fe8 0759f420 vld!VisualLeakDetector::getTls+0xfc [c:\build\vld\v24c\src\vld.cpp @ 1075]
6dcf 0759f404 09dda74b 05480fd0 0000004c 0759f45c vld!VisualLeakDetector::enabled+0x23 [c:\build\vld\v24c\src\vld.cpp @ 982]
6dd0 0759f420 7614ea43 00490000 00000000 00000018 vld!VisualLeakDetector::_HeapAlloc+0x2b [c:\build\vld\v24c\src\vld_hooks.cpp @ 1617]
6dd1 0759f434 7614ea5f 762466bc 00000018 0759f450 ole32!CRetailMalloc_Alloc+0x16 [d:\w7rtm\com\ole32\com\class\memapi.cxx @ 641]
```
*To workaround this problem*, you can load VLD ASAP when application starts so it will get a TLS slot <64.
For a detailed explanation of Windows TLS internals, please refer to [Thread Local Storage, part 2: Explicit TLS](http://www.nynaeve.net/?p=181).
```
#include <windows.h>
#include <thread>
#include <chrono>
#include <memory>
int main(int argc, wchar_t *argv[]) {
for (int i = 0; i < 0x40; ++i)
TlsAlloc();
HMODULE h_vld = LoadLibraryA("vld.dll");
typedef void(*vld_enable_t)(void);
auto vld_enable = (vld_enable_t)::GetProcAddress(h_vld, "VLDGlobalEnable");
vld_enable();
std::thread([]() {std::make_shared<int>(); }).join();
return 0;
}
```
On Windows, by default Thread Local Storage (TLS) has 0x40 slots. Later it is expanded by 0x400 more slots. These expansion slots are created on demand when TLS APIs TlsAlloc/TlsFree/TlsGetValue/TlsSetValue are invoked in current thread. And the expansion is achieved by calling Windows API RtlAllocateHeap. When TLS APIs are invoked the first time with slot number >= 0x40 in a thread which hasn't expand before, TLS expansion will be triggered.
To assist troubleshooting memory leak issues, memory allocation APIs, including `RtlAllocateHeap`, are hooked by VLD.
When a memory allocation happens, VLD will store the information in its TLS slot to avoid contention and reduce performance impact. When VLD is assigned with a TLS slot >= 0x40 and a memory allocation happens in a thread that hasn't expand TLS, the access to TLS slot from VLD will trigger another TLS expansion.
However, the expansion will call `RtlAllocateHeap` to allocate memory and the record of this memory allocation will be saved into TLS slot by VLD, which will again trigger another TLS expansion... In this way, The program will enter infinite recursion.
The call stack of this crash will be looks like:
```
6dc9 0759f314 09ddbfcc 00000042 0a16b870 09defbd0 KERNELBASE!TlsSetValue+0x4f
6dca 0759f360 09ddc1a3 09defbd0 00490000 0759f38c vld!VisualLeakDetector::getTls+0xfc [c:\build\vld\v24c\src\vld.cpp @ 1075]
6dcb 0759f370 09dda74b 0baa5930 00000008 0759f69c vld!VisualLeakDetector::enabled+0x23 [c:\build\vld\v24c\src\vld.cpp @ 982]
6dcc 0759f38c 75c445cf 00490000 00000008 00001000 vld!VisualLeakDetector::_HeapAlloc+0x2b [c:\build\vld\v24c\src\vld_hooks.cpp @ 1617]
6dcd 0759f3a8 09ddbfcc 00000042 0a16b870 09defbd0 KERNELBASE!TlsSetValue+0x4f
6dce 0759f3f4 09ddc1a3 09defbd0 05480fe8 0759f420 vld!VisualLeakDetector::getTls+0xfc [c:\build\vld\v24c\src\vld.cpp @ 1075]
6dcf 0759f404 09dda74b 05480fd0 0000004c 0759f45c vld!VisualLeakDetector::enabled+0x23 [c:\build\vld\v24c\src\vld.cpp @ 982]
6dd0 0759f420 7614ea43 00490000 00000000 00000018 vld!VisualLeakDetector::_HeapAlloc+0x2b [c:\build\vld\v24c\src\vld_hooks.cpp @ 1617]
6dd1 0759f434 7614ea5f 762466bc 00000018 0759f450 ole32!CRetailMalloc_Alloc+0x16 [d:\w7rtm\com\ole32\com\class\memapi.cxx @ 641]
```
*To workaround this problem*, you can load VLD ASAP when application starts so it will get a TLS slot <64.
For a detailed explanation of Windows TLS internals, please refer to [Thread Local Storage, part 2: Explicit TLS](http://www.nynaeve.net/?p=181).
```
#include <windows.h>
#include <thread>
#include <chrono>
#include <memory>
int main(int argc, wchar_t *argv[]) {
for (int i = 0; i < 0x40; ++i)
TlsAlloc();
HMODULE h_vld = LoadLibraryA("vld.dll");
typedef void(*vld_enable_t)(void);
auto vld_enable = (vld_enable_t)::GetProcAddress(h_vld, "VLDGlobalEnable");
vld_enable();
std::thread([]() {std::make_shared<int>(); }).join();
return 0;
}
```