You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Checked build JIT assertion (pfnHelper != NULL) when accessing __declspec(thread) TLS from IJW/C++CLI managed entry points #133538
When a mixed-mode (IJW/C++/CLI) assembly declares a native, file-scope __declspec(thread) global (wrapped in #pragma unmanaged/#pragma managed) and that global is accessed from a public ref class static method, calling into that method from managed code under a Checked CoreCLR build crashes with a JIT assertion:
The assertion fires in CEECodeGenInfo::getHelperFtn (src/coreclr/vm/jitinterface.cpp:11404, in a FEATURE_PORTABLE_ENTRYPOINTS code path), where the JIT's Lowering::LowerDirectCall requests a JIT helper function pointer and the helper table entry is unpopulated.
Repro
Minimal repro (Windows, x64, Checked build):
test.cpp (compiled as an IJW/C++CLI assembly, e.g. via /clr):
#pragma unmanaged
__declspec(thread) int s_tlsFieldData = 51966;
#pragma managed
public ref classTlsTest
{
public:staticintTest()
{
int value = s_tlsFieldData;
s_tlsFieldData = value;
s_tlsFieldData = 100;
return s_tlsFieldData;
}
};
Managed caller (any invocation mechanism — both plain reflection MethodInfo.Invoke and UnsafeAccessor reproduce identically):
Running this against a Checked CoreCLR build crashes with the assertion above. The same code runs successfully against Debug and Release builds. Switching the native storage from __declspec(thread) to a managed [System::ThreadStatic] field on the ref class avoids the crash entirely.
Analysis so far
The crash is independent of the managed→native call mechanism: it reproduces identically whether the native method is invoked via reflection (MethodInfo.Invoke) or via [UnsafeAccessor]/[UnsafeAccessorType].
The crash is tied specifically to __declspec(thread) TLS storage accessed through the IJW-hosted managed entry point; using [System::ThreadStatic] instead does not reproduce the crash.
This was discovered while converting src/tests regression tests that originally used IL .data tls declarations to C++/CLI (see Convert .data tls IL tests to C++/CLI #133533), where a reviewer requested using true native __declspec(thread) TLS (rather than [System::ThreadStatic]) "to actually be testing the right feature." Reintroducing __declspec(thread) reproduced this crash in all four converted tests.
Activity
dotnet-policy-service commentedon Sep 9, 2026
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.
Address PR review feedback for TLS C++/CLI tests
MichalStrehovsky commentedon Sep 10, 2026
This is likely a dup of #42187
dotnet-policy-service commentedon Sep 10, 2026
Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.
Support IJW native TLS static field access (dotnet#136183)