Use second user TLS slot to avoid using reserved fields in the TEB (issue #1078)

This commit is contained in:
daanx 2025-05-02 16:12:20 -07:00
parent 2c34250f43
commit f3e92b1edd
2 changed files with 22 additions and 9 deletions

View file

@ -208,19 +208,20 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce
#elif _WIN32 && MI_WIN_USE_FIXED_TLS && !defined(MI_WIN_USE_FLS)
// On windows we can store the thread-local heap at a fixed TLS slot to avoid
// thread-local initialization checks in the fast path. This uses a fixed location
// in the TCB though (last user-reserved slot by default) which may clash with other applications.
// thread-local initialization checks in the fast path.
// We always use the second user TLS slot (the first one is always allocated already),
// and at initialization (`windows/prim.c`) we call TlsAlloc and verify
// we indeed get the second slot (and fail otherwise).
// Todo: we could make the Tls slot completely dynamic but that would require
// an extra read of the static Tls slot instead of using a constant offset.
#define MI_HAS_TLS_SLOT 2 // 2 = we can reliably initialize the slot (saving a test on each malloc)
#if MI_WIN_USE_FIXED_TLS > 1
#define MI_TLS_SLOT (MI_WIN_USE_FIXED_TLS)
#elif MI_SIZE_SIZE == 4
#define MI_TLS_SLOT (0x710) // Last user-reserved slot <https://en.wikipedia.org/wiki/Win32_Thread_Information_Block>
// #define MI_TLS_SLOT (0xF0C) // Last TlsSlot (might clash with other app reserved slot)
#define MI_TLS_SLOT (0x0E18) // Second User TLS slot <https://en.wikipedia.org/wiki/Win32_Thread_Information_Block>
#else
#define MI_TLS_SLOT (0x888) // Last user-reserved slot <https://en.wikipedia.org/wiki/Win32_Thread_Information_Block>
// #define MI_TLS_SLOT (0x1678) // Last TlsSlot (might clash with other app reserved slot)
#define MI_TLS_SLOT (0x1488) // Second User TLS slot <https://en.wikipedia.org/wiki/Win32_Thread_Information_Block>
#endif
static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept {

View file

@ -631,8 +631,20 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) {
MI_UNUSED(reserved);
MI_UNUSED(module);
#if MI_TLS_SLOT >= 2
if ((reason==DLL_PROCESS_ATTACH || reason==DLL_THREAD_ATTACH) && mi_prim_get_default_heap() == NULL) {
_mi_heap_set_default_direct((mi_heap_t*)&_mi_heap_empty);
if (reason==DLL_PROCESS_ATTACH) {
const DWORD tls_slot = TlsAlloc();
if (tls_slot != 1) {
_mi_error_message(EFAULT, "unable to allocate the second TLS slot (rebuild without MI_WIN_USE_FIXED_TLS?)\n");
}
}
if (reason==DLL_PROCESS_ATTACH || reason==DLL_THREAD_ATTACH) {
if (mi_prim_get_default_heap() == NULL) {
_mi_heap_set_default_direct((mi_heap_t*)&_mi_heap_empty);
}
#if MI_DEBUG
void* const p = TlsGetValue(1);
mi_assert_internal(p == (void*)&_mi_heap_empty);
#endif
}
#endif
if (reason==DLL_PROCESS_ATTACH) {