From 457a4f5e5e610b1b4b9e5f9b248f3fb6056844d7 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Wed, 4 Mar 2026 15:39:27 +0100 Subject: [PATCH 1/5] Dispose event listener created in InMemoryAssemblyLoadContextManager. --- .../InMemoryAuto/InMemoryAssemblyLoadContextManager.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Cms.DevelopmentMode.Backoffice/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs b/src/Umbraco.Cms.DevelopmentMode.Backoffice/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs index 3285c081343c..034e3d3838e6 100644 --- a/src/Umbraco.Cms.DevelopmentMode.Backoffice/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs +++ b/src/Umbraco.Cms.DevelopmentMode.Backoffice/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs @@ -3,13 +3,16 @@ namespace Umbraco.Cms.DevelopmentMode.Backoffice.InMemoryAuto; -internal sealed class InMemoryAssemblyLoadContextManager +internal sealed class InMemoryAssemblyLoadContextManager : IDisposable { private UmbracoAssemblyLoadContext? _currentAssemblyLoadContext; public InMemoryAssemblyLoadContextManager() => AssemblyLoadContext.Default.Resolving += OnResolvingDefaultAssemblyLoadContext; + public void Dispose() => + AssemblyLoadContext.Default.Resolving -= OnResolvingDefaultAssemblyLoadContext; + private string? _modelsAssemblyLocation; public string? ModelsAssemblyLocation => _modelsAssemblyLocation; From 48bb5698861bfba54150e0fe7f627185ab74855e Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Wed, 4 Mar 2026 15:39:59 +0100 Subject: [PATCH 2/5] Use using to dispose ICryptoTransform in MemberPasswordHasher. --- src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs index 7caf52fc2951..56135d95a77d 100644 --- a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs +++ b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs @@ -161,8 +161,8 @@ private bool IsSuccessfulLegacyPassword(string hashedPassword, string providedPa private static string DecryptLegacyPassword(string encryptedPassword, SymmetricAlgorithm algorithm) { using var memoryStream = new MemoryStream(); - ICryptoTransform cryptoTransform = algorithm.CreateDecryptor(); - var cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write); + using ICryptoTransform cryptoTransform = algorithm.CreateDecryptor(); + using var cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write); var buf = Convert.FromBase64String(encryptedPassword); cryptoStream.Write(buf, 0, 32); cryptoStream.FlushFinalBlock(); From e7f89515944c17fe425df786179c134726d34265 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Wed, 4 Mar 2026 15:40:59 +0100 Subject: [PATCH 3/5] Dispose CancellationTokenSource in DatabaseServerMessenger. --- src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index 5ee571c1e884..a220a7c27bdd 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -343,6 +343,7 @@ protected virtual void Dispose(bool disposing) if (disposing) { _syncIdle.Dispose(); + _cancellationTokenSource.Dispose(); } _disposedValue = true; From 62c4b3d88fa31ed955ede6d7d152d1e63615cc9b Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Wed, 4 Mar 2026 15:42:48 +0100 Subject: [PATCH 4/5] Dispose deserialized JsonDocument in CacheInstructionService. --- src/Umbraco.Infrastructure/Services/CacheInstructionService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs b/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs index 0f38b4d96a9d..a79404b2ab86 100644 --- a/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs +++ b/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs @@ -291,6 +291,7 @@ private int ProcessDatabaseInstructions(CacheRefresherCollection cacheRefreshers } List instructionBatch = GetAllInstructions(jsonInstructions?.RootElement); + jsonInstructions?.Dispose(); // Process as per-normal. var success = ProcessDatabaseInstructions(cacheRefreshers, instructionBatch, instruction, processed, cancellationToken, ref lastId); From 8353ad59697b66732607b883eec033d58da351b5 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Wed, 4 Mar 2026 15:57:17 +0100 Subject: [PATCH 5/5] Use try/finally to ensure dispose. --- .../Services/CacheInstructionService.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs b/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs index a79404b2ab86..8987c6466445 100644 --- a/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs +++ b/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs @@ -290,8 +290,17 @@ private int ProcessDatabaseInstructions(CacheRefresherCollection cacheRefreshers continue; } - List instructionBatch = GetAllInstructions(jsonInstructions?.RootElement); - jsonInstructions?.Dispose(); + // Dispose the JsonDocument once we've extracted instructions from its RootElement. + // Use try/finally to ensure pooled buffers are returned even if retrieving the instructions throws. + List instructionBatch; + try + { + instructionBatch = GetAllInstructions(jsonInstructions?.RootElement); + } + finally + { + jsonInstructions?.Dispose(); + } // Process as per-normal. var success = ProcessDatabaseInstructions(cacheRefreshers, instructionBatch, instruction, processed, cancellationToken, ref lastId);