From c970b879f899ef5e77b1e3cec3601394d5f8afb5 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sun, 17 Aug 2025 14:15:56 -0700 Subject: [PATCH 1/2] IJW workaround --- src/coreclr/vm/ceeload.cpp | 9 +++++++++ src/coreclr/vm/ceeload.h | 2 ++ src/coreclr/vm/ceemain.cpp | 13 ++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index eb3a2d8015ccd5..50b44b6ff6761f 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -3746,10 +3746,19 @@ void SaveManagedCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv) #endif } +static bool g_fIJWLoaded = false; + void Module::SetIsIJWFixedUp() { LIMITED_METHOD_CONTRACT; InterlockedOr((LONG*)&m_dwTransientFlags, IS_IJW_FIXED_UP); + g_fIJWLoaded = true; +} + +bool Module::HasAnyIJWBeenLoaded() +{ + LIMITED_METHOD_CONTRACT; + return g_fIJWLoaded; } #endif // !DACCESS_COMPILE diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 5fee2e09f4bf79..0f9936e47f864c 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -1476,6 +1476,8 @@ class Module : public ModuleBase BOOL IsIJWFixedUp() { return m_dwTransientFlags & IS_IJW_FIXED_UP; } void SetIsIJWFixedUp(); + static bool HasAnyIJWBeenLoaded(); + BOOL IsBeingUnloaded() { return m_dwTransientFlags & IS_BEING_UNLOADED; } void SetBeingUnloaded(); void StartUnload(); diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 3df24664ff2df5..31ddf88222a595 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -1815,7 +1815,18 @@ static void OsAttachThread(void* thread) if (t_flsState == FLS_STATE_INVOKED) { - _ASSERTE_ALL_BUILDS(!"Attempt to execute managed code after the .NET runtime thread state has been destroyed."); + // Managed C++ may run managed code in DllMain (e.g. during DLL_PROCESS_DETACH to run global destructors). This is + // not supported and unreliable. Historically, it happened to work most of the time. For backward compatibility, + // suppress this assert in release builds if we have encountered any mixed mode binaries. + // compatibility. + if (Module::HasAnyIJWBeenLoaded()) + { + _ASSERTE(!"Attempt to execute managed code after the .NET runtime thread state has been destroyed."); + } + else + { + _ASSERTE_ALL_BUILDS(!"Attempt to execute managed code after the .NET runtime thread state has been destroyed."); + } } t_flsState = FLS_STATE_ARMED; From ebf826e08193d1503b7b9d971e5bc4f9f5eb846f Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sun, 17 Aug 2025 18:05:16 -0700 Subject: [PATCH 2/2] Update src/coreclr/vm/ceemain.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/vm/ceemain.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 31ddf88222a595..a75353ec28f990 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -1818,7 +1818,6 @@ static void OsAttachThread(void* thread) // Managed C++ may run managed code in DllMain (e.g. during DLL_PROCESS_DETACH to run global destructors). This is // not supported and unreliable. Historically, it happened to work most of the time. For backward compatibility, // suppress this assert in release builds if we have encountered any mixed mode binaries. - // compatibility. if (Module::HasAnyIJWBeenLoaded()) { _ASSERTE(!"Attempt to execute managed code after the .NET runtime thread state has been destroyed.");