From ddf5b5b35140d2f6b3936cc74d6b6054c71bba30 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:55:40 -0700 Subject: [PATCH 1/5] Always dispose PEReader in ResourceUpdater --- .../managed/Microsoft.NET.HostModel/ResourceUpdater.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs index e4791a6bb14e99..94ff0be384dba6 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs @@ -333,10 +333,11 @@ public void Dispose() public void Dispose(bool disposing) { - if (disposing && !leaveOpen) + if (disposing) { _reader.Dispose(); - stream.Dispose(); + if (!leaveOpen) + stream.Dispose(); } } } From 7c9e8003cef4a6e3e007d5e5e624480cb30f392c Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:00:02 -0700 Subject: [PATCH 2/5] Practice good Dispose hygene --- .../managed/Microsoft.NET.HostModel/ResourceUpdater.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs index 94ff0be384dba6..ea3d396307ce2b 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs @@ -13,7 +13,7 @@ namespace Microsoft.NET.HostModel /// /// Provides methods for modifying the embedded native resources in a PE image. /// - public class ResourceUpdater : IDisposable + public sealed class ResourceUpdater : IDisposable { private readonly FileStream stream; private readonly PEReader _reader; @@ -325,19 +325,21 @@ private static void ThrowExceptionForInvalidUpdate() "Update handle is invalid. This instance may not be used for further updates"); } - public void Dispose() + void IDisposable.Dispose() { Dispose(true); GC.SuppressFinalize(this); } - public void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { _reader.Dispose(); if (!leaveOpen) + { stream.Dispose(); + } } } } From 4fce069835934ba95d0b9955418bd78a0c16939d Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:23:08 -0700 Subject: [PATCH 3/5] Revert Dispose visibility changes --- .../managed/Microsoft.NET.HostModel/ResourceUpdater.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs index ea3d396307ce2b..40a3d78a8bcf36 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs @@ -325,13 +325,13 @@ private static void ThrowExceptionForInvalidUpdate() "Update handle is invalid. This instance may not be used for further updates"); } - void IDisposable.Dispose() + public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } - private void Dispose(bool disposing) + public void Dispose(bool disposing) { if (disposing) { From 83225a7474947af5984a3e31d14dfc715e3323ea Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 24 Sep 2025 13:21:22 -0700 Subject: [PATCH 4/5] Add unit test to validate dispose behavior --- .../ResourceUpdaterTests.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/ResourceUpdaterTests.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/ResourceUpdaterTests.cs index 30e3efdf1027db..2f25839507bbfa 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/ResourceUpdaterTests.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/ResourceUpdaterTests.cs @@ -23,7 +23,7 @@ class TempFile : IDisposable public TempFile() { _path = Path.GetTempFileName(); - Stream = new FileStream(_path, FileMode.Open); + Stream = new FileStream(_path, FileMode.Open, FileAccess.ReadWrite, FileShare.None); } public void Dispose() @@ -169,6 +169,25 @@ void AddResource_AddTwoSameUShortTypeWithDifferName() } } + [Fact] + void DisposeWithLeaveOpenDisposesPEReader() + { + using var tempFile = GetCurrentAssemblyMemoryStream(); + PEReader? peReader = null; + + using (var updater = new ResourceUpdater(tempFile.Stream, leaveOpen: true)) + { + FieldInfo? readerField = typeof(ResourceUpdater).GetField("_reader", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.NotNull(readerField); + peReader = Assert.IsType(readerField.GetValue(updater)); + _ = peReader.PEHeaders; + } + + Assert.NotNull(peReader); + + Assert.Throws(() => _ = peReader!.PEHeaders); + } + [Fact] void AddResourcesFromPEImage() { From 7ffeea1594e03b1c8b6fe8a9430ddd2909614111 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 25 Sep 2025 13:02:45 -0700 Subject: [PATCH 5/5] Make Dispose(bool) private --- .../managed/Microsoft.NET.HostModel/ResourceUpdater.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs index 40a3d78a8bcf36..1873e38956038e 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs @@ -331,7 +331,7 @@ public void Dispose() GC.SuppressFinalize(this); } - public void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) {