Fix ILVerifier holding files open (#89127)
authorMike Voorhees <mrvoorhe@users.noreply.github.com>
Wed, 19 Jul 2023 10:41:22 +0000 (06:41 -0400)
committerGitHub <noreply@github.com>
Wed, 19 Jul 2023 10:41:22 +0000 (03:41 -0700)
There were a couple things to fix

1) `PEReader` implements `IDisposable` and needs to be disposed.  Not least because it is managing the lifetime of the streams opened by `File.OpenRead` calls inside `ILVerifier`

2) In order to dispose of of the pereaders, add `IDisposable` to `ILVerifier` and add a `using` to the caller that creates a new instance.

(1) and (2) fix the issues with files being held open.

While looking at the code, I didn't see a reason why `TryLoadAssemblyFromFolder` couldn't check the `_assemblyCache` before creating a opening a new stream and creating a new pereader.  I don't think this was causing any issues.  It just seemed like a harmless just-in-case change.

src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ILVerifier.cs
src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs

index 8ef1b79..1f907e7 100644 (file)
@@ -1,6 +1,7 @@
 // Copyright (c) .NET Foundation and contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
+using System;
 using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.IO;
@@ -14,7 +15,7 @@ using Mono.Linker.Tests.Extensions;
 #nullable enable
 namespace Mono.Linker.Tests.TestCasesRunner
 {
-       sealed class ILVerifier : ILVerify.IResolver
+       sealed class ILVerifier : ILVerify.IResolver, IDisposable
        {
                readonly Verifier _verifier;
                readonly NPath _assemblyFolder;
@@ -82,6 +83,9 @@ namespace Mono.Linker.Tests.TestCasesRunner
 
                bool TryLoadAssemblyFromFolder (string assemblyName, NPath folder, [NotNullWhen (true)] out PEReader? peReader)
                {
+                       if (_assemblyCache.TryGetValue (assemblyName, out peReader))
+                               return true;
+
                        Assembly? assembly = null;
                        string assemblyPath = Path.Join (folder.ToString (), assemblyName);
                        if (File.Exists (assemblyPath + ".dll"))
@@ -124,6 +128,13 @@ namespace Mono.Linker.Tests.TestCasesRunner
                {
                        return $"IL Verification error:\n{result.Message}";
                }
+
+               public void Dispose()
+               {
+                       foreach(var reader in _assemblyCache.Values)
+                               reader.Dispose ();
+                       _assemblyCache.Clear ();
+               }
        }
 }
 #nullable restore
index acdcc29..bef6cd7 100644 (file)
@@ -51,7 +51,7 @@ namespace Mono.Linker.Tests.TestCasesRunner
 
                static void VerifyIL (NPath pathToAssembly, AssemblyDefinition linked)
                {
-                       var verifier = new ILVerifier (pathToAssembly);
+                       using var verifier = new ILVerifier (pathToAssembly);
                        foreach (var result in verifier.Results)
                                Assert.Fail (ILVerifier.GetErrorMessage (result));
                }