From 33a966cd1c7b2cd82f68cca929088f3d76d5691b Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Wed, 28 Jan 2026 17:31:53 -0800 Subject: [PATCH 01/14] Add config switch to fully disable hot-reload --- .../Reflection/Metadata/MetadataUpdater.cs | 2 +- .../Reflection/Metadata/MetadataUpdater.cs | 2 +- .../src/System.Private.CoreLib.Shared.projitems | 1 + .../Reflection/Metadata/MetadataUpdater.cs | 15 +++++++++++++++ .../tests/ApplyUpdateTest.cs | 16 ++++++++++++++++ .../Reflection/Metadata/MetadataUpdater.cs | 4 ++-- 6 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index f0b6774ac45503..01cf81f01ef424 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -61,6 +61,6 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDel /// Returns true if the apply assembly update is enabled and available. /// [FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")] - public static bool IsSupported { get; } = IsApplyUpdateSupported(); + public static bool IsSupported { get; } = !IsHotReloadDisabled && IsApplyUpdateSupported(); } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index fa929ccba5d438..563f2e27f7fc50 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -5,7 +5,7 @@ namespace System.Reflection.Metadata { - public static class MetadataUpdater + public static partial class MetadataUpdater { public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDelta, ReadOnlySpan ilDelta, ReadOnlySpan pdbDelta) { diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 2c5f234cc2d163..16f43f682dfe8d 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -793,6 +793,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs new file mode 100644 index 00000000000000..585350ee3fc23a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection.Metadata +{ + public static partial class MetadataUpdater + { + /// + /// Returns true if hot reload is explicitly disabled via the DOTNET_HOTRELOAD_DISABLED environment variable + /// or the System.Reflection.Metadata.HotReloadDisabled AppContext switch set to true. + /// + internal static bool IsHotReloadDisabled => + AppContextConfigHelper.GetBooleanConfig("System.Reflection.Metadata.HotReloadDisabled", "DOTNET_HOTRELOAD_DISABLED"); + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index c8576441586296..ab5388b7c5149d 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Microsoft.DotNet.RemoteExecutor; using Xunit; namespace System.Reflection.Metadata @@ -1157,5 +1158,20 @@ void TestIncreaseMetadataRowSize() Assert.Equal("x800", pars[0].Name); }); } + + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsRemoteExecutorSupported))] + void TestHotReloadDisabledEnvironmentVariable() + { + // Check that DOTNET_HOTRELOAD_DISABLED=1 disables MetadataUpdater.IsSupported. + var options = new RemoteInvokeOptions(); + options.StartInfo.EnvironmentVariables.Add( + ApplyUpdateUtil.DotNetModifiableAssembliesSwitch, ApplyUpdateUtil.DotNetModifiableAssembliesValue); + options.StartInfo.EnvironmentVariables.Add("DOTNET_HOTRELOAD_DISABLED", "1"); + + RemoteExecutor.Invoke(static () => + { + Assert.False(MetadataUpdater.IsSupported); + }, options).Dispose(); + } } } diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index 67306e03081e28..749e1d474f2de7 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -7,7 +7,7 @@ namespace System.Reflection.Metadata { - public static class MetadataUpdater + public static partial class MetadataUpdater { /// /// Updates the specified assembly using the provided metadata, IL and PDB deltas. @@ -51,7 +51,7 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDel internal static string GetCapabilities() => s_ApplyUpdateCapabilities.Value; [FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")] - public static bool IsSupported { get; } = ApplyUpdateEnabled(justComponentCheck: 0) != 0; + public static bool IsSupported { get; } = !IsHotReloadDisabled && ApplyUpdateEnabled(justComponentCheck: 0) != 0; private static readonly Lazy s_ApplyUpdateCapabilities = new Lazy(InitializeApplyUpdateCapabilities); From c1447482106ddcf79f557b43765f2e5d003234ff Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Fri, 30 Jan 2026 13:33:23 -0800 Subject: [PATCH 02/14] Revert new config switch, extend existing environment variable --- .../Reflection/Metadata/MetadataUpdater.cs | 2 +- .../Reflection/Metadata/MetadataUpdater.cs | 2 +- src/coreclr/vm/assemblynative.cpp | 3 ++- src/coreclr/vm/ceeload.cpp | 3 ++- src/coreclr/vm/eeconfig.cpp | 15 ++++++++++++- src/coreclr/vm/eeconfig.h | 17 ++++++++++---- .../System.Private.CoreLib.Shared.projitems | 1 - .../Reflection/Metadata/MetadataUpdater.cs | 15 ------------- .../tests/ApplyUpdateTest.cs | 9 ++++---- .../tests/ApplyUpdateUtil.cs | 1 + .../Reflection/Metadata/MetadataUpdater.cs | 4 ++-- src/mono/mono/component/hot_reload-stub.c | 2 +- src/mono/mono/component/hot_reload.c | 22 +++++++++++-------- src/mono/mono/metadata/metadata-update.h | 8 ++++--- 14 files changed, 60 insertions(+), 44 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index 01cf81f01ef424..f0b6774ac45503 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -61,6 +61,6 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDel /// Returns true if the apply assembly update is enabled and available. /// [FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")] - public static bool IsSupported { get; } = !IsHotReloadDisabled && IsApplyUpdateSupported(); + public static bool IsSupported { get; } = IsApplyUpdateSupported(); } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index 563f2e27f7fc50..fa929ccba5d438 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -5,7 +5,7 @@ namespace System.Reflection.Metadata { - public static partial class MetadataUpdater + public static class MetadataUpdater { public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDelta, ReadOnlySpan ilDelta, ReadOnlySpan pdbDelta) { diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index a962e22b5fe31c..5430b277d09df1 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -1419,7 +1419,8 @@ extern "C" BOOL QCALLTYPE AssemblyNative_IsApplyUpdateSupported() BEGIN_QCALL; #ifdef FEATURE_METADATA_UPDATER - result = CORDebuggerAttached() || g_pConfig->ForceEnc() || g_pConfig->DebugAssembliesModifiable(); + result = (g_pConfig->ModifiableAssemblies() != MODIFIABLE_ASSM_NONE) && + (CORDebuggerAttached() || g_pConfig->ForceEnc() || g_pConfig->ModifiableAssemblies() == MODIFIABLE_ASSM_DEBUG); #endif END_QCALL; diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 1860164c62e19a..a66f86575ef880 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -523,7 +523,8 @@ void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits) #ifdef DEBUGGING_SUPPORTED if (IsEditAndContinueCapable()) { - BOOL setEnC = (newBits & DACF_ENC_ENABLED) != 0 || g_pConfig->ForceEnc() || (g_pConfig->DebugAssembliesModifiable() && AreJITOptimizationsDisabled()); + BOOL setEnC = (newBits & DACF_ENC_ENABLED) != 0 || g_pConfig->ForceEnc() || + (g_pConfig->ModifiableAssemblies() == MODIFIABLE_ASSM_DEBUG && AreJITOptimizationsDisabled()); if (setEnC) { EnableEditAndContinue(); diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 3ac8563207491a..e64e0b4894706d 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -445,7 +445,20 @@ HRESULT EEConfig::sync() NewArrayHolder wszModifiableAssemblies; IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DOTNET_MODIFIABLE_ASSEMBLIES, &wszModifiableAssemblies)); if (wszModifiableAssemblies) - fDebugAssembliesModifiable = _wcsicmp(wszModifiableAssemblies, W("debug")) == 0; + { + if (_wcsicmp(wszModifiableAssemblies, W("debug")) == 0) + { + modifiableAssemblies = MODIFIABLE_ASSM_DEBUG; + } + else if (_wcsicmp(wszModifiableAssemblies, W("none")) == 0) + { + modifiableAssemblies = MODIFIABLE_ASSM_NONE; + } + else + { + modifiableAssemblies = MODIFIABLE_ASSM_UNSET; + } + } } pReadyToRunExcludeList = NULL; diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index fadd2515f2cf6a..a4854ea3b29bdc 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -43,6 +43,15 @@ enum { OPT_BLENDED, OPT_RANDOM, OPT_DEFAULT = OPT_BLENDED }; +enum ClrModifiableAssemblies { + /* modifiable assemblies are implicitly disabled */ + MODIFIABLE_ASSM_UNSET = 0, + /* modifiable assemblies are explicitly disabled */ + MODIFIABLE_ASSM_NONE = 1, + /* assemblies with the Debug flag are modifiable */ + MODIFIABLE_ASSM_DEBUG = 2, +}; + enum ParseCtl { parseAll, // parse entire config file stopAfterRuntimeSection // stop after ... section @@ -404,9 +413,9 @@ class EEConfig // Loader bool ExcludeReadyToRun(LPCUTF8 assemblyName) const; - bool StressLog() const { LIMITED_METHOD_CONTRACT; return fStressLog; } - bool ForceEnc() const { LIMITED_METHOD_CONTRACT; return fForceEnc; } - bool DebugAssembliesModifiable() const { LIMITED_METHOD_CONTRACT; return fDebugAssembliesModifiable; } + bool StressLog() const { LIMITED_METHOD_CONTRACT; return fStressLog; } + bool ForceEnc() const { LIMITED_METHOD_CONTRACT; return fForceEnc; } + ClrModifiableAssemblies ModifiableAssemblies() const { LIMITED_METHOD_CONTRACT; return modifiableAssemblies; } // Optimizations to improve working set @@ -569,7 +578,7 @@ class EEConfig bool fStressLog; bool fForceEnc; - bool fDebugAssembliesModifiable; + ClrModifiableAssemblies modifiableAssemblies; #ifdef _DEBUG // interop logging diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 16f43f682dfe8d..2c5f234cc2d163 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -793,7 +793,6 @@ - diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs deleted file mode 100644 index 585350ee3fc23a..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Reflection.Metadata -{ - public static partial class MetadataUpdater - { - /// - /// Returns true if hot reload is explicitly disabled via the DOTNET_HOTRELOAD_DISABLED environment variable - /// or the System.Reflection.Metadata.HotReloadDisabled AppContext switch set to true. - /// - internal static bool IsHotReloadDisabled => - AppContextConfigHelper.GetBooleanConfig("System.Reflection.Metadata.HotReloadDisabled", "DOTNET_HOTRELOAD_DISABLED"); - } -} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index ab5388b7c5149d..85fb6bd3f86e74 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -1160,17 +1160,18 @@ void TestIncreaseMetadataRowSize() } [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsRemoteExecutorSupported))] - void TestHotReloadDisabledEnvironmentVariable() + void TestDisableMetadataUpdate() { - // Check that DOTNET_HOTRELOAD_DISABLED=1 disables MetadataUpdater.IsSupported. var options = new RemoteInvokeOptions(); options.StartInfo.EnvironmentVariables.Add( - ApplyUpdateUtil.DotNetModifiableAssembliesSwitch, ApplyUpdateUtil.DotNetModifiableAssembliesValue); - options.StartInfo.EnvironmentVariables.Add("DOTNET_HOTRELOAD_DISABLED", "1"); + ApplyUpdateUtil.DotNetModifiableAssembliesSwitch, ApplyUpdateUtil.DotNetModifiableAssembliesDisabledValue); RemoteExecutor.Invoke(static () => { Assert.False(MetadataUpdater.IsSupported); + var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.ClassWithCustomAttributeUpdates).Assembly; + Assert.Throws(() => + MetadataUpdater.ApplyUpdate(assm, ReadOnlySpan.Empty, ReadOnlySpan.Empty, ReadOnlySpan.Empty)); }, options).Dispose(); } } diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs index b74144dceffd59..f96ddb119e4397 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs @@ -11,6 +11,7 @@ namespace System.Reflection.Metadata public class ApplyUpdateUtil { internal const string DotNetModifiableAssembliesSwitch = "DOTNET_MODIFIABLE_ASSEMBLIES"; internal const string DotNetModifiableAssembliesValue = "debug"; + internal const string DotNetModifiableAssembliesDisabledValue = "none"; /// Whether ApplyUpdate is supported by the environment, test configuration, and runtime. /// diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index 749e1d474f2de7..9ef9562f55fd60 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -7,7 +7,7 @@ namespace System.Reflection.Metadata { - public static partial class MetadataUpdater + public static class MetadataUpdater { /// /// Updates the specified assembly using the provided metadata, IL and PDB deltas. @@ -51,7 +51,7 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDel internal static string GetCapabilities() => s_ApplyUpdateCapabilities.Value; [FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")] - public static bool IsSupported { get; } = !IsHotReloadDisabled && ApplyUpdateEnabled(justComponentCheck: 0) != 0; + public static bool IsSupported { get; } = ApplyUpdateEnabled(justComponentCheck: 0) != 0; private static readonly Lazy s_ApplyUpdateCapabilities = new Lazy(InitializeApplyUpdateCapabilities); diff --git a/src/mono/mono/component/hot_reload-stub.c b/src/mono/mono/component/hot_reload-stub.c index 73fc1fba50f381..f4d1b8dd1ec587 100644 --- a/src/mono/mono/component/hot_reload-stub.c +++ b/src/mono/mono/component/hot_reload-stub.c @@ -190,7 +190,7 @@ gboolean hot_reload_stub_update_enabled (int *modifiable_assemblies_out) { if (modifiable_assemblies_out) - *modifiable_assemblies_out = MONO_MODIFIABLE_ASSM_NONE; + *modifiable_assemblies_out = MONO_MODIFIABLE_ASSM_UNSET; return false; } diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index e5614bb0788aec..18c2cc2cc7e73b 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -344,13 +344,13 @@ gboolean hot_reload_update_enabled (int *modifiable_assemblies_out) { static gboolean inited = FALSE; - static int modifiable = MONO_MODIFIABLE_ASSM_NONE; + static int modifiable = MONO_MODIFIABLE_ASSM_UNSET; gboolean result = FALSE; if (!inited) { modifiable = hot_reload_update_enabled_slow_check (NULL); inited = TRUE; - result = (modifiable != MONO_MODIFIABLE_ASSM_NONE); + result = (modifiable != MONO_MODIFIABLE_ASSM_UNSET); if (result) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Metadata update enabled for debuggable assemblies"); } @@ -363,15 +363,17 @@ hot_reload_update_enabled (int *modifiable_assemblies_out) /** * checks the DOTNET_MODIFIABLE_ASSEMBLIES environment value. if it is recognized returns the * aporporiate MONO_MODIFIABLE_ASSM_ enum value. if it is unset or uncrecognized returns - * MONO_MODIFIABLE_ASSM_NONE and writes the value to \c env_invalid_val_out, if it is non-NULL; + * MONO_MODIFIABLE_ASSM_UNSET and writes the value to \c env_invalid_val_out, if it is non-NULL; */ static int hot_reload_update_enabled_slow_check (char **env_invalid_val_out) { - int modifiable = MONO_MODIFIABLE_ASSM_NONE; + int modifiable = MONO_MODIFIABLE_ASSM_UNSET; char *val = g_getenv (DOTNET_MODIFIABLE_ASSEMBLIES); if (val && !g_strcasecmp (val, "debug")) { modifiable = MONO_MODIFIABLE_ASSM_DEBUG; + } else if (val && !g_strcasecmp (val, "none")) { + modifiable = MONO_MODIFIABLE_ASSM_NONE; } else { /* unset or unrecognized value */ if (env_invalid_val_out != NULL) { @@ -389,10 +391,12 @@ assembly_update_supported (MonoImage *image_base, MonoError *error) int modifiable = 0; char *invalid_env_val = NULL; modifiable = hot_reload_update_enabled_slow_check (&invalid_env_val); - if (modifiable == MONO_MODIFIABLE_ASSM_NONE) { + if (modifiable == MONO_MODIFIABLE_ASSM_UNSET) { mono_error_set_invalid_operation (error, "The assembly '%s' cannot be edited or changed, because environment variable DOTNET_MODIFIABLE_ASSEMBLIES is set to '%s', not 'Debug'", image_base->name, invalid_env_val); g_free (invalid_env_val); return FALSE; + } else if (modifiable == MONO_MODIFIABLE_ASSM_NONE) { + return FALSE; } else if (!mono_assembly_is_jit_optimizer_disabled (image_base->assembly)) { mono_error_set_invalid_operation (error, "The assembly '%s' cannot be edited or changed, because it does not have a System.Diagnostics.DebuggableAttribute with the DebuggingModes.DisableOptimizations flag (editing Release build assemblies is not supported)", image_base->name); return FALSE; @@ -953,11 +957,11 @@ delta_info_initialize_mutants (const MonoImage *base, const BaselineInfo *base_i { const char *src = src_base + src_offset; char *dst = dst_base + dst_offset; - + /* copy src to dst, via a temporary to adjust for size differences */ /* FIXME: unaligned access, endianness */ guint32 tmp; - + switch (src_col_size) { case 1: tmp = *(guint8*)src; @@ -971,7 +975,7 @@ delta_info_initialize_mutants (const MonoImage *base, const BaselineInfo *base_i default: g_assert_not_reached (); } - + /* FIXME: unaligned access, endianness */ switch (dst_col_size) { case 1: @@ -1436,7 +1440,7 @@ delta_info_mutate_row (MonoImage *image_dmeta, DeltaInfo *cur_delta, guint32 log /* The complication here is that we want the mutant table to look like the table in * the baseline image with respect to column widths, but the delta tables are generally coming in - * uncompressed (4-byte columns). And we have already adjusted the baseline image column widths + * uncompressed (4-byte columns). And we have already adjusted the baseline image column widths * so we can use memcpy here. */ diff --git a/src/mono/mono/metadata/metadata-update.h b/src/mono/mono/metadata/metadata-update.h index 4e45c60439b5c3..d46ad4b4a4e779 100644 --- a/src/mono/mono/metadata/metadata-update.h +++ b/src/mono/mono/metadata/metadata-update.h @@ -14,10 +14,12 @@ void mono_metadata_update_init (void); enum MonoModifiableAssemblies { - /* modifiable assemblies are disabled */ - MONO_MODIFIABLE_ASSM_NONE = 0, + /* modifiable assemblies are implicitly disabled */ + MONO_MODIFIABLE_ASSM_UNSET = 0, + /* modifiable assemblies are explicitly disabled */ + MONO_MODIFIABLE_ASSM_NONE = 1, /* assemblies with the Debug flag are modifiable */ - MONO_MODIFIABLE_ASSM_DEBUG = 1, + MONO_MODIFIABLE_ASSM_DEBUG = 2, }; typedef MonoStreamHeader* (*MetadataHeapGetterFunc) (MonoImage*); From 043fb9804431e69750715161536d098ab34e7fe1 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Fri, 30 Jan 2026 14:00:17 -0800 Subject: [PATCH 03/14] Fix typos --- .../src/System/Reflection/Metadata/MetadataUpdater.cs | 2 +- src/mono/mono/component/hot_reload.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index 9ef9562f55fd60..67306e03081e28 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -51,7 +51,7 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDel internal static string GetCapabilities() => s_ApplyUpdateCapabilities.Value; [FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")] - public static bool IsSupported { get; } = ApplyUpdateEnabled(justComponentCheck: 0) != 0; + public static bool IsSupported { get; } = ApplyUpdateEnabled(justComponentCheck: 0) != 0; private static readonly Lazy s_ApplyUpdateCapabilities = new Lazy(InitializeApplyUpdateCapabilities); diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 18c2cc2cc7e73b..788361cc05b5b1 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -362,7 +362,7 @@ hot_reload_update_enabled (int *modifiable_assemblies_out) /** * checks the DOTNET_MODIFIABLE_ASSEMBLIES environment value. if it is recognized returns the - * aporporiate MONO_MODIFIABLE_ASSM_ enum value. if it is unset or uncrecognized returns + * appropriate MONO_MODIFIABLE_ASSM_ enum value. if it is unset or unrecognized returns * MONO_MODIFIABLE_ASSM_UNSET and writes the value to \c env_invalid_val_out, if it is non-NULL; */ static int From 1055754b09e8f32b43751377375435340c230966 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Mon, 2 Feb 2026 11:33:10 -0800 Subject: [PATCH 04/14] Fix incorrect logic --- src/mono/mono/component/hot_reload.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 788361cc05b5b1..a91e07cda4ded0 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -350,7 +350,7 @@ hot_reload_update_enabled (int *modifiable_assemblies_out) if (!inited) { modifiable = hot_reload_update_enabled_slow_check (NULL); inited = TRUE; - result = (modifiable != MONO_MODIFIABLE_ASSM_UNSET); + result = (modifiable == MONO_MODIFIABLE_ASSM_DEBUG); if (result) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Metadata update enabled for debuggable assemblies"); } @@ -396,6 +396,7 @@ assembly_update_supported (MonoImage *image_base, MonoError *error) g_free (invalid_env_val); return FALSE; } else if (modifiable == MONO_MODIFIABLE_ASSM_NONE) { + mono_error_set_invalid_operation (error, "The assembly '%s' cannot be edited or changed, because environment variable DOTNET_MODIFIABLE_ASSEMBLIES is set to 'none', not 'Debug'", image_base->name); return FALSE; } else if (!mono_assembly_is_jit_optimizer_disabled (image_base->assembly)) { mono_error_set_invalid_operation (error, "The assembly '%s' cannot be edited or changed, because it does not have a System.Diagnostics.DebuggableAttribute with the DebuggingModes.DisableOptimizations flag (editing Release build assemblies is not supported)", image_base->name); From 01e1d75cac44565c5b90cf3ab7061c421bb5d1ba Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Tue, 3 Feb 2026 17:07:22 -0800 Subject: [PATCH 05/14] Disable EnC when DOTNET_MODIFIABLE_ASSEMBLIES is none --- src/coreclr/vm/ceeload.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index a66f86575ef880..6b575131a15798 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -523,8 +523,9 @@ void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits) #ifdef DEBUGGING_SUPPORTED if (IsEditAndContinueCapable()) { - BOOL setEnC = (newBits & DACF_ENC_ENABLED) != 0 || g_pConfig->ForceEnc() || - (g_pConfig->ModifiableAssemblies() == MODIFIABLE_ASSM_DEBUG && AreJITOptimizationsDisabled()); + BOOL setEnC = (g_pConfig->ModifiableAssemblies() != MODIFIABLE_ASSM_NONE) && + ((newBits & DACF_ENC_ENABLED) != 0 || g_pConfig->ForceEnc() || + (g_pConfig->ModifiableAssemblies() == MODIFIABLE_ASSM_DEBUG && AreJITOptimizationsDisabled())); if (setEnC) { EnableEditAndContinue(); From 69974037bf16c496790d961db6927f124a13d0fd Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Mon, 9 Feb 2026 15:58:40 -0800 Subject: [PATCH 06/14] Fix a test --- src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index 85fb6bd3f86e74..2d8b1f11d897e5 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -1170,8 +1170,10 @@ void TestDisableMetadataUpdate() { Assert.False(MetadataUpdater.IsSupported); var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.ClassWithCustomAttributeUpdates).Assembly; + var metadataDelta = new byte[20]; + var ilDelta = new byte[20]; Assert.Throws(() => - MetadataUpdater.ApplyUpdate(assm, ReadOnlySpan.Empty, ReadOnlySpan.Empty, ReadOnlySpan.Empty)); + MetadataUpdater.ApplyUpdate(assm, metadataDelta, ilDelta, ReadOnlySpan.Empty)); }, options).Dispose(); } } From 954601635f240bea27aaafd9d736b08c9b2b4642 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Mon, 9 Feb 2026 16:03:07 -0800 Subject: [PATCH 07/14] Update a config value description --- src/coreclr/inc/clrconfigvalues.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 8d2652c6c0fbc8..46863f11f93c67 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -381,7 +381,7 @@ CONFIG_DWORD_INFO(INTERNAL_MD_MiniMDBreak, W("MD_MiniMDBreak"), 0, "ASSERT when CONFIG_DWORD_INFO(INTERNAL_MD_PreSaveBreak, W("MD_PreSaveBreak"), 0, "ASSERT when calling CMiniMdRw::PreSave") CONFIG_DWORD_INFO(INTERNAL_MD_RegMetaBreak, W("MD_RegMetaBreak"), 0, "ASSERT when creating RegMeta class") CONFIG_DWORD_INFO(INTERNAL_MD_RegMetaDump, W("MD_RegMetaDump"), 0, "Dump MD in 4 functions (?)") -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_MODIFIABLE_ASSEMBLIES, W("MODIFIABLE_ASSEMBLIES"), "Enables hot reload on debug built assemblies with the 'debug' keyword", CLRConfig::LookupOptions::TrimWhiteSpaceFromStringValue); +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_MODIFIABLE_ASSEMBLIES, W("MODIFIABLE_ASSEMBLIES"), "Enables hot reload on debug built assemblies with the 'debug' keyword, 'none' explicitly disables it even when debugger is attached", CLRConfig::LookupOptions::TrimWhiteSpaceFromStringValue); // Metadata - mscordbi only - this flag is only intended to mitigate potential issues in bug fix 458597. RETAIL_CONFIG_DWORD_INFO(EXTERNAL_MD_PreserveDebuggerMetadataMemory, W("MD_PreserveDebuggerMetadataMemory"), 0, "Save all versions of metadata memory in the debugger when debuggee metadata is updated") From 8f3de22d447260fe10fdebda6f0605e7007a94f4 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Mon, 9 Feb 2026 17:23:30 -0800 Subject: [PATCH 08/14] Update test logic --- .../System.Runtime.Loader/tests/ApplyUpdateTest.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index 2d8b1f11d897e5..dbc7817ef71e31 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -1163,9 +1163,12 @@ void TestIncreaseMetadataRowSize() void TestDisableMetadataUpdate() { var options = new RemoteInvokeOptions(); - options.StartInfo.EnvironmentVariables.Add( - ApplyUpdateUtil.DotNetModifiableAssembliesSwitch, ApplyUpdateUtil.DotNetModifiableAssembliesDisabledValue); + options.StartInfo.EnvironmentVariables.Add(ApplyUpdateUtil.DotNetModifiableAssembliesSwitch, + ApplyUpdateUtil.DotNetModifiableAssembliesValue); + RemoteExecutor.Invoke(static () => { Assert.True(MetadataUpdater.IsSupported); }, options).Dispose(); + + options.StartInfo.EnvironmentVariables[ApplyUpdateUtil.DotNetModifiableAssembliesSwitch] = ApplyUpdateUtil.DotNetModifiableAssembliesDisabledValue; RemoteExecutor.Invoke(static () => { Assert.False(MetadataUpdater.IsSupported); From f51173353d819f96c48d80c2fa7c9bc73ab36c08 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Mon, 9 Feb 2026 17:31:22 -0800 Subject: [PATCH 09/14] Initialize modifiableAssemblies when unset --- src/coreclr/vm/eeconfig.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index e64e0b4894706d..ca7df2adca9b84 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -117,6 +117,7 @@ HRESULT EEConfig::Init() INDEBUG(fStressLog = true;) fDebuggable = false; + modifiableAssemblies = MODIFIABLE_ASSM_UNSET; #ifdef _DEBUG fExpandAllOnLoad = false; @@ -454,10 +455,6 @@ HRESULT EEConfig::sync() { modifiableAssemblies = MODIFIABLE_ASSM_NONE; } - else - { - modifiableAssemblies = MODIFIABLE_ASSM_UNSET; - } } } From 0602e6a6da21f2d58f526e82fb51b1aa08157345 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Thu, 12 Feb 2026 10:57:14 -0800 Subject: [PATCH 10/14] Apply pr suggestions --- src/coreclr/vm/eeconfig.h | 12 ++++++------ .../System.Runtime.Loader/tests/ApplyUpdateTest.cs | 2 +- .../System.Runtime.Loader/tests/ApplyUpdateUtil.cs | 3 +++ src/mono/mono/component/hot_reload.c | 9 ++++++++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index a4854ea3b29bdc..22e9d5b2ea54ca 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -44,12 +44,12 @@ enum { OPT_BLENDED, OPT_DEFAULT = OPT_BLENDED }; enum ClrModifiableAssemblies { - /* modifiable assemblies are implicitly disabled */ - MODIFIABLE_ASSM_UNSET = 0, - /* modifiable assemblies are explicitly disabled */ - MODIFIABLE_ASSM_NONE = 1, - /* assemblies with the Debug flag are modifiable */ - MODIFIABLE_ASSM_DEBUG = 2, + /* modifiable assemblies are implicitly disabled */ + MODIFIABLE_ASSM_UNSET = 0, + /* modifiable assemblies are explicitly disabled */ + MODIFIABLE_ASSM_NONE = 1, + /* assemblies with the Debug flag are modifiable */ + MODIFIABLE_ASSM_DEBUG = 2, }; enum ParseCtl { diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index dbc7817ef71e31..07a96455ef38d5 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -1159,7 +1159,7 @@ void TestIncreaseMetadataRowSize() }); } - [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsRemoteExecutorSupported))] + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsRemoteExecutorSupportedAndFeatureCapable))] void TestDisableMetadataUpdate() { var options = new RemoteInvokeOptions(); diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs index f96ddb119e4397..6a8f37fb1c62d5 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs @@ -22,6 +22,9 @@ public class ApplyUpdateUtil { public static bool IsSupported => (IsModifiableAssembliesSet || IsRemoteExecutorSupported) && (!IsMonoRuntime || IsSupportedMonoConfiguration); + /// true if RemoteExecutor is available and the runtime supports metadata updates. + public static bool IsRemoteExecutorSupportedAndFeatureCapable => IsSupported && IsRemoteExecutorSupported; + /// true if the current runtime was not launched with the appropriate settings for applying /// updates (DOTNET_MODIFIABLE_ASSEMBLIES unset), but we can use the remote executor to /// launch a child process that has the right setting. diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index a91e07cda4ded0..d493473c851376 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -372,8 +372,10 @@ hot_reload_update_enabled_slow_check (char **env_invalid_val_out) char *val = g_getenv (DOTNET_MODIFIABLE_ASSEMBLIES); if (val && !g_strcasecmp (val, "debug")) { modifiable = MONO_MODIFIABLE_ASSM_DEBUG; + g_free (val); } else if (val && !g_strcasecmp (val, "none")) { modifiable = MONO_MODIFIABLE_ASSM_NONE; + g_free (val); } else { /* unset or unrecognized value */ if (env_invalid_val_out != NULL) { @@ -392,7 +394,12 @@ assembly_update_supported (MonoImage *image_base, MonoError *error) char *invalid_env_val = NULL; modifiable = hot_reload_update_enabled_slow_check (&invalid_env_val); if (modifiable == MONO_MODIFIABLE_ASSM_UNSET) { - mono_error_set_invalid_operation (error, "The assembly '%s' cannot be edited or changed, because environment variable DOTNET_MODIFIABLE_ASSEMBLIES is set to '%s', not 'Debug'", image_base->name, invalid_env_val); + if (invalid_env_val == NULL) + { + mono_error_set_invalid_operation (error, "The assembly '%s' cannot be edited or changed, because environment variable DOTNET_MODIFIABLE_ASSEMBLIES is not set", image_base->name); + } else { + mono_error_set_invalid_operation (error, "The assembly '%s' cannot be edited or changed, because environment variable DOTNET_MODIFIABLE_ASSEMBLIES is set to '%s', not 'Debug'", image_base->name, invalid_env_val); + } g_free (invalid_env_val); return FALSE; } else if (modifiable == MONO_MODIFIABLE_ASSM_NONE) { From d2f68c57fdd5bdd3c1f34a37fbc81d4cc86e1fb6 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Thu, 12 Feb 2026 14:52:03 -0800 Subject: [PATCH 11/14] Fix failing test --- .../System.Runtime.Loader/tests/ApplyUpdateTest.cs | 6 ++---- .../System.Runtime.Loader/tests/ApplyUpdateUtil.cs | 8 +++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index 07a96455ef38d5..196d9c1679632d 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -1162,10 +1162,8 @@ void TestIncreaseMetadataRowSize() [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsRemoteExecutorSupportedAndFeatureCapable))] void TestDisableMetadataUpdate() { - var options = new RemoteInvokeOptions(); - - options.StartInfo.EnvironmentVariables.Add(ApplyUpdateUtil.DotNetModifiableAssembliesSwitch, - ApplyUpdateUtil.DotNetModifiableAssembliesValue); + RemoteInvokeOptions options = null; + ApplyUpdateUtil.AddRemoteInvokeOptions(ref options); RemoteExecutor.Invoke(static () => { Assert.True(MetadataUpdater.IsSupported); }, options).Dispose(); options.StartInfo.EnvironmentVariables[ApplyUpdateUtil.DotNetModifiableAssembliesSwitch] = ApplyUpdateUtil.DotNetModifiableAssembliesDisabledValue; diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs index 6a8f37fb1c62d5..b21c7e02770b1d 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs @@ -104,9 +104,15 @@ internal static void AddRemoteInvokeOptions (ref RemoteInvokeOptions options) { options = options ?? new RemoteInvokeOptions(); options.StartInfo.EnvironmentVariables.Add(DotNetModifiableAssembliesSwitch, DotNetModifiableAssembliesValue); - /* Ask mono to use .dpdb data to generate sequence points even without a debugger attached */ + /* Ask mono to use .dpdb data to generate sequence points even without a debugger attached. + Also propagate MONO_ENV_OPTIONS so the child process runs in interpreter mode. */ if (IsMonoRuntime) + { AppendEnvironmentVariable(options.StartInfo.EnvironmentVariables, "MONO_DEBUG", "gen-seq-points"); + string monoEnvOptions = Environment.GetEnvironmentVariable("MONO_ENV_OPTIONS"); + if (!string.IsNullOrEmpty(monoEnvOptions)) + options.StartInfo.EnvironmentVariables.Add("MONO_ENV_OPTIONS", monoEnvOptions); + } } private static void AppendEnvironmentVariable(System.Collections.Specialized.StringDictionary env, string key, string addedValue) From fdf4476a7747cca76690f3d8d6f3e3831f18394c Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Fri, 13 Feb 2026 11:26:26 -0800 Subject: [PATCH 12/14] Fix failing tests --- src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs index b21c7e02770b1d..2d5304391677ca 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs @@ -110,7 +110,7 @@ Also propagate MONO_ENV_OPTIONS so the child process runs in interpreter mode. * { AppendEnvironmentVariable(options.StartInfo.EnvironmentVariables, "MONO_DEBUG", "gen-seq-points"); string monoEnvOptions = Environment.GetEnvironmentVariable("MONO_ENV_OPTIONS"); - if (!string.IsNullOrEmpty(monoEnvOptions)) + if (!string.IsNullOrEmpty(monoEnvOptions) && !options.StartInfo.EnvironmentVariables.ContainsKey("MONO_ENV_OPTIONS")) options.StartInfo.EnvironmentVariables.Add("MONO_ENV_OPTIONS", monoEnvOptions); } } From bebc6696473579e4c1332569f6d05b4976a8aa03 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Fri, 13 Feb 2026 15:29:47 -0800 Subject: [PATCH 13/14] Revert failing test fixes, skip the test for mono --- .../System.Runtime.Loader/tests/ApplyUpdateTest.cs | 2 +- .../System.Runtime.Loader/tests/ApplyUpdateUtil.cs | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index 196d9c1679632d..9d4396a70914a5 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -1159,7 +1159,7 @@ void TestIncreaseMetadataRowSize() }); } - [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsRemoteExecutorSupportedAndFeatureCapable))] + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsRemoteExecutorSupportedAndFeatureCapable), nameof(ApplyUpdateUtil.IsNotMonoRuntime))] void TestDisableMetadataUpdate() { RemoteInvokeOptions options = null; diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs index 2d5304391677ca..6a8f37fb1c62d5 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs @@ -104,15 +104,9 @@ internal static void AddRemoteInvokeOptions (ref RemoteInvokeOptions options) { options = options ?? new RemoteInvokeOptions(); options.StartInfo.EnvironmentVariables.Add(DotNetModifiableAssembliesSwitch, DotNetModifiableAssembliesValue); - /* Ask mono to use .dpdb data to generate sequence points even without a debugger attached. - Also propagate MONO_ENV_OPTIONS so the child process runs in interpreter mode. */ + /* Ask mono to use .dpdb data to generate sequence points even without a debugger attached */ if (IsMonoRuntime) - { AppendEnvironmentVariable(options.StartInfo.EnvironmentVariables, "MONO_DEBUG", "gen-seq-points"); - string monoEnvOptions = Environment.GetEnvironmentVariable("MONO_ENV_OPTIONS"); - if (!string.IsNullOrEmpty(monoEnvOptions) && !options.StartInfo.EnvironmentVariables.ContainsKey("MONO_ENV_OPTIONS")) - options.StartInfo.EnvironmentVariables.Add("MONO_ENV_OPTIONS", monoEnvOptions); - } } private static void AppendEnvironmentVariable(System.Collections.Specialized.StringDictionary env, string key, string addedValue) From 89a6d013e72fb53f40a0444314b975ada2180166 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Fri, 13 Feb 2026 16:56:13 -0800 Subject: [PATCH 14/14] Fix hot_reload_update_enabled returning FALSE after first call --- src/mono/mono/component/hot_reload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index d493473c851376..d5ee8b6c9bd876 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -346,7 +346,7 @@ hot_reload_update_enabled (int *modifiable_assemblies_out) static gboolean inited = FALSE; static int modifiable = MONO_MODIFIABLE_ASSM_UNSET; - gboolean result = FALSE; + static gboolean result = FALSE; if (!inited) { modifiable = hot_reload_update_enabled_slow_check (NULL); inited = TRUE;