|
32 | 32 | using System.Collections;
|
33 | 33 | using System.Collections.Generic;
|
34 | 34 | using System.IO;
|
| 35 | +using System.IO.MemoryMappedFiles; |
35 | 36 | using System.Linq;
|
36 | 37 | using System.Reflection;
|
37 | 38 |
|
@@ -61,6 +62,7 @@ public class DirectoryAssemblyResolver : IAssemblyResolver {
|
61 | 62 |
|
62 | 63 | public ICollection<string> SearchDirectories {get; private set;}
|
63 | 64 |
|
| 65 | + readonly List<MemoryMappedViewStream> viewStreams = new List<MemoryMappedViewStream> (); |
64 | 66 | Dictionary<string, AssemblyDefinition?> cache;
|
65 | 67 | bool loadDebugSymbols;
|
66 | 68 | Action<TraceLevel, string> logger;
|
@@ -103,6 +105,10 @@ protected virtual void Dispose (bool disposing)
|
103 | 105 | e.Value?.Dispose ();
|
104 | 106 | }
|
105 | 107 | cache.Clear ();
|
| 108 | + foreach (var viewStream in viewStreams) { |
| 109 | + viewStream.Dispose (); |
| 110 | + } |
| 111 | + viewStreams.Clear (); |
106 | 112 | }
|
107 | 113 |
|
108 | 114 | public Dictionary<string, AssemblyDefinition?> ToResolverCache ()
|
@@ -160,14 +166,41 @@ protected virtual AssemblyDefinition ReadAssembly (string file)
|
160 | 166 | SymbolStream = loadReaderParameters.SymbolStream,
|
161 | 167 | };
|
162 | 168 | try {
|
163 |
| - return AssemblyDefinition.ReadAssembly (file, reader_parameters); |
| 169 | + return LoadFromMemoryMappedFile (file, reader_parameters); |
164 | 170 | } catch (Exception ex) {
|
165 | 171 | logger (
|
166 | 172 | TraceLevel.Verbose,
|
167 | 173 | $"Failed to read '{file}' with debugging symbols. Retrying to load it without it. Error details are logged below.");
|
168 | 174 | logger (TraceLevel.Verbose, $"{ex.ToString ()}");
|
169 | 175 | reader_parameters.ReadSymbols = false;
|
170 |
| - return AssemblyDefinition.ReadAssembly (file, reader_parameters); |
| 176 | + return LoadFromMemoryMappedFile (file, reader_parameters); |
| 177 | + } |
| 178 | + } |
| 179 | + |
| 180 | + AssemblyDefinition LoadFromMemoryMappedFile (string file, ReaderParameters options) |
| 181 | + { |
| 182 | + // We can't use MemoryMappedFile when ReadWrite is true |
| 183 | + if (options.ReadWrite) { |
| 184 | + return AssemblyDefinition.ReadAssembly (file, options); |
| 185 | + } |
| 186 | + |
| 187 | + MemoryMappedViewStream? viewStream = null; |
| 188 | + try { |
| 189 | + // Create stream because CreateFromFile(string, ...) uses FileShare.None which is too strict |
| 190 | + using var fileStream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false); |
| 191 | + using var mappedFile = MemoryMappedFile.CreateFromFile ( |
| 192 | + fileStream, null, fileStream.Length, MemoryMappedFileAccess.Read, HandleInheritability.None, true); |
| 193 | + viewStream = mappedFile.CreateViewStream (0, 0, MemoryMappedFileAccess.Read); |
| 194 | + |
| 195 | + AssemblyDefinition result = ModuleDefinition.ReadModule (viewStream, options).Assembly; |
| 196 | + viewStreams.Add (viewStream); |
| 197 | + |
| 198 | + // We transferred the ownership of the viewStream to the collection. |
| 199 | + viewStream = null; |
| 200 | + |
| 201 | + return result; |
| 202 | + } finally { |
| 203 | + viewStream?.Dispose (); |
171 | 204 | }
|
172 | 205 | }
|
173 | 206 |
|
|
0 commit comments