-
Notifications
You must be signed in to change notification settings - Fork 564
[Xamarin.Android.Build.Tasks] Dispose DirectoryAssemblyResolver instances #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This was referenced Sep 24, 2016
Contributor
|
Looks ok. The Required PR for Java.Interop has been merge so we just need to update this one with the new hash (and the ReaderParameter TODO bits) and it should be good. |
…nces Context: https://bugzilla.xamarin.com/show_bug.cgi?id=44529 Commit 1d65825 bumped to Cecil 0.10.0-beta1-v2 and Java.Interop/a1d3ecc8, which likewise uses Cecil 0.10.0-beta1-v2. Among the various API changes in Cecil 0.10.x vs. Cecil 0.9.x is a change to `Mono.Cecil.IAssemblyResolver`, implemented by `Java.Interop.Tools.Cecil.DirectoryAssemblyResolver`, to implement the `IDisposable` interface. Java.Interop/a1d3ecc8 added a `DirectoryAssemblyResolver.Dispose()` method, but this method didn't *do* anything. Cecil 0.10.0-beta1-v2 also has a *semantic* change vs. Cecil 0.9.x: `AssemblyDefinition` is no longer a "purely in-memory" construct. Instead, it holds a `System.IO.Stream` to the assembly it's reading (unless `Mono.Cecil.ReaderParameters.InMemory` is `true`). This semantic change means that an assembly can't be read from and written to at the same time via different mechanisms, so long as there is an `AssemblyDefinition` instance to that file. Which brings us to (private) Bug #44529, in which an `IOException` is thrown from the `<StripEmbeddedLibraries/>` task: Error executing task StripEmbeddedLibraries: System.IO.IOException: Sharing violation on path .../obj/Release/linksrc/Xamarin.Android.NUnitLite.dll at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) [0x0025f] in <253a3790b2c44512bbca8669ecfc1822>:0 at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) [0x00000] in <253a3790b2c44512bbca8669ecfc1822>:0 at (wrapper remoting-invoke-with-check) System.IO.FileStream:.ctor (string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare) at Mono.Cecil.ModuleDefinition.GetFileStream (System.String fileName, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) [0x00007] in :0 at Mono.Cecil.ModuleDefinition.Write (System.String fileName, Mono.Cecil.WriterParameters parameters) [0x00007] in :0 at Mono.Cecil.AssemblyDefinition.Write (System.String fileName, Mono.Cecil.WriterParameters parameters) [0x00001] in :0 at Xamarin.Android.Tasks.StripEmbeddedLibraries.Execute () [0x0034a] in <3d5202a5d4874a76a99388021bf1ab1a>:0 The underlying cause of the `IOException` is twofold: 1. `AssemblyDefinition` instances now hold a `FileStream` to the file they're reading from (and optionally writing to), and this `FileStream` will be kept open until `AssemblyDefinition.Dispose()` is called. 2. Nothing in `Xamarin.Android.Build.Tasks` calls `AssemblyDefinition.Dispose()`. Nor should anything in `Xamarin.Android.Build.Tasks` call `AssemblyDefinition.Dispose()`! (Almost) All `AssemblyDefinition` instances are *cached* within `DirectoryAssemblyResolver` instances, and nothing calls `DirectoryAssemblyResolver.Dispose()` either! (Not that this matters *too* much, becuase `DirectoryAssemblyResolver.Dispose()` is currently a no-op.) There is no sane reasoning here: so long as we're using `DirectoryAssemblyResolver`, we're going to have more files open (compared to when Cecil 0.9.x was used), which can result in file sharing problems and the above `IOException`. The way foward is: 1. `Java.Interop.Tools.Cecil.DirectoryAssemblyResolver` needs to be updated so that [`DirectoryAssemblyResolver.Dispose()` is useful][0], i.e. that it will `Dispose()` of all held `AssemblyDefinition` instances. 2. Bump to Java.Interop/084e9f7f to pick up (1). 3. `Xamarin.Android.Build.Tasks.dll` needs to be updated so that `DirectoryAssemblyResolver.Dispose()` is used. 4. All code, in particular `Xamarin.Andorid.Build.Tasks.dll`, needs to be reviewed to ensure it doesn't do anything "stupid" with `AssemblyDefinition` instances and/or `DirectoryAssemblyResolver.` Examples of "stupid" things include: * `Dispose()`ing of the return value from `DirectoryAssemblyResolver.Load()`: resolver.Load (assemblyName).Dispose(); * Treating `AssemblyDefinition` instances in a manner inconsistent with how `DirectoryAssemblyResolver` loads them. `DirectoryAssemblyResolver` will be getting a new constructor overload which takes an `Mono.Cecil.ReaderParameters` parameter; the default will be the default Cecil behavior, which is for read-only behavior. Thus, trying to use the `AssemblyDefinition` in a "write" context will fail: var r = new DirectoryAssemblyResolver (...); var a = r.Load (assemblyName); a.Write (); // BOOM [0]: dotnet/java-interop#88
712be22 to
5544f92
Compare
Contributor
|
LGTM |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Supersedes: #231
Requires: dotnet/java-interop#88
Context: https://bugzilla.xamarin.com/show_bug.cgi?id=44529
Commit 1d65825 bumped to Cecil 0.10.0-beta1-v2 and
Java.Interop/a1d3ecc8, which likewise uses Cecil 0.10.0-beta1-v2.
Among the various API changes in Cecil 0.10.x vs. Cecil 0.9.x is a
change to
Mono.Cecil.IAssemblyResolver, implemented byJava.Interop.Tools.Cecil.DirectoryAssemblyResolver, to implement theIDisposableinterface.Java.Interop/a1d3ecc8 added a
DirectoryAssemblyResolver.Dispose()method, but this method didn't do anything.
Cecil 0.10.0-beta1-v2 also has a semantic change vs. Cecil 0.9.x:
AssemblyDefinitionis no longer a "purely in-memory" construct.Instead, it holds a
System.IO.Streamto the assembly it's reading(unless
Mono.Cecil.ReaderParameters.InMemoryistrue).This semantic change means that an assembly can't be read from and
written to at the same time via different mechanisms, so long as there
is an
AssemblyDefinitioninstance to that file.Which brings us to (private) Bug #44529, in which an
IOExceptionisthrown from the
<StripEmbeddedLibraries/>task:The underlying cause of the
IOExceptionis twofold:AssemblyDefinitioninstances now hold aFileStreamto the filethey're reading from (and optionally writing to), and this
FileStreamwill be kept open untilAssemblyDefinition.Dispose()is called.Xamarin.Android.Build.TaskscallsAssemblyDefinition.Dispose().Nor should anything in
Xamarin.Android.Build.TaskscallAssemblyDefinition.Dispose()! (Almost) AllAssemblyDefinitioninstances are cached within
DirectoryAssemblyResolverinstances,and nothing calls
DirectoryAssemblyResolver.Dispose()either!(Not that this matters too much, becuase
DirectoryAssemblyResolver.Dispose()is currently a no-op.)There is no sane reasoning here: so long as we're using
DirectoryAssemblyResolver, we're going to have more files open(compared to when Cecil 0.9.x was used), which can result in file
sharing problems and the above
IOException.The way foward is:
Java.Interop.Tools.Cecil.DirectoryAssemblyResolverneeds to beupdated so that
DirectoryAssemblyResolver.Dispose()is useful, i.e. that itwill
Dispose()of all heldAssemblyDefinitioninstances.Bump to Java.Interop/084e9f7f to pick up (1).
Xamarin.Android.Build.Tasks.dllneeds to be updated so thatDirectoryAssemblyResolver.Dispose()is used.All code, in particular
Xamarin.Andorid.Build.Tasks.dll, needs tobe reviewed to ensure it doesn't do anything "stupid" with
AssemblyDefinitioninstances and/orDirectoryAssemblyResolver.Examples of "stupid" things include:
Dispose()ing of the return value fromDirectoryAssemblyResolver.Load():Treating
AssemblyDefinitioninstances in a manner inconsistentwith how
DirectoryAssemblyResolverloads them.DirectoryAssemblyResolverwill be getting a new constructoroverload which takes an
Mono.Cecil.ReaderParametersparameter;the default will be the default Cecil behavior, which is for
read-only behavior. Thus, trying to use the
AssemblyDefinitionin a "write" context will fail: