From a80f17c200365b8dff7c2f14743c9c5f3b9efd67 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 29ea5a358fd2cd..adfe056bdbe20b 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -3744,10 +3744,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 98853750cd44a9..3cea27da8fbcee 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -1513,6 +1513,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 4ad3ae3cc78925..b308afb64e2627 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -1702,7 +1702,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 4876c0bb91aadb8eafe7c14f00205ec6dd0f93ff 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 b308afb64e2627..4be75dc9158969 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -1705,7 +1705,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.");