-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Fix WinMD handling in System.Reflection.MetadataLoadContext #58344
Conversation
Add a test to prevent regressions
src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs
Outdated
Show resolved
Hide resolved
|
The MetadataLoadContext should work on Browser, but the test requires better MetadataAssemblyResolver implementation
Can this make it into 7.0.0 milestone? It's a pretty simple fix for a bug that makes it impossible to properly process any Windows Runtime WinMD file using |
src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs
Outdated
Show resolved
Hide resolved
...flection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/MetadataTable.cs
Show resolved
Hide resolved
{ | ||
Debug.Assert(!handle.IsNil); | ||
Debug.Assert(factory != null); | ||
|
||
int index = handle.GetToken().GetTokenRowNumber() - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary (was there an issue converting from token to row number) or just simplification?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's at least half of the fix. System.Reflection
handles WinMDs fine, because it knows about virtual AssemblyRefs
. System.Reflection.MetadataLoadContext
didn't. I dropped the wrong/incomplete GetTokenRowNumber
impl from System.Reflection.MetadataLoadContext
, and used the correct System.Reflection
one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
System.Reflection handles WinMDs fine, because it knows about virtual AssemblyRefs
I assume you mean System.Reflection.Metadata
, not System.Reflection
via the reader option MetadataReaderOptions.ApplyWindowsRuntimeProjections
and the resulting MetadataKind.WindowsMetadata
enum value.
{ | ||
return new MetadataTable<T, EcmaModule>(Reader.GetTableRowCount(tableIndex)); | ||
int rowCount = tableIndex switch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style\nit: for a simple two-case switch I think an if
statement is more appropriate.
@@ -3074,5 +3074,63 @@ internal static class TestData | |||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + | |||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + | |||
"AAAAAAAAAAAAAAAA"); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there is an attempt in tests to use an actual .winmd
file, as in the original issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a reduced copy that still exhibits the issue. The only snag was having to use ILASM from .NET Framework instead of .NET one, which silently generated .winmd
with wrong metadata version, which is a crucial thing for reproducing the issue. The original .winmd
files (Windows SDK UnionMetadata one, and the ones from Windows installation folder) are too big to put in a test.
@andrew-boyarshin can you explain a bit your scenario? I assume some UWP work given the original |
@steveharter I need to parse and generate some code for Windows SDK. Let's say, for something like SharpGen. To that end, I know I need to load WinMD and iterate through every type and method. Back in .NET Framework days, I know I needed reflection-only assembly loading. Now, the recommended replacement is |
System.Runtime still fails to resolve on Browser. WinMD parsing on Browser is questionable enough. Though, with better MetadataAssemblyResolver impl it should still work. Making this new unit test be Browser-aware is out-of-scope for this fix. The issue to be fixed is not related to assembly loading at all.
I've been told the WinMD format has enough differences with ECMA-335 that support should be considered a non-goal. Not saying we shouldn't accept this but does this actually represent full support? /cc @jkotas @jkoritzinsky |
@AaronRobinsonMSFT well, this fix allowed me to parse the entire |
How would you explain (e.g. in documentation) what is and what is not supported after these fixes? The most complex part of the WinRT interop support are type projections. This does not seem to be handling the type projections at all. I doubt that you can actually use this as .NET type system without the type projections. We have intentionally removed the built-in support for WinRT interop in #35318 . The WinRT interop is being developed independently on .NET runtime in https://github.com/microsoft/CsWinRT/ . |
@jkotas this is independent of WinRT interop support removed in 5.0. This is merely a library that leverages |
The abstraction to use for building It is not possible to build ildasm using |
@jkotas fine. I have presented a patch that allowed me to parse an entire Windows Runtime API surface with a high-level API. It also reduces code complexity by reusing existing code and dropping generic parameter that is always known to be By the way, I'd be interested to read about the differences between .NET type system and WinRT type system, without taking projecting |
The point of this discussion is whether we are comfortable with supporting this scenario going forward. WinRT is developed independently on .NET these days. System.Reflection.MetadataLoadContext was not designed for reading .winmd files. There are scenarios today where System.Reflection.MetadataLoadContext won't work well for reading .winmd files, and this set is likely to grow over time.
This simplification is definitely welcomed. Thank you!
I am not aware of comprehensive up-to-date document that lists all differences. I can give you one example: Names in assembly references are irrelevant in WinRT type system. The name in .winmd assembly references maps to correct file name some of the time. It is fragile to depend on it. The WinRT type system specifies algorithm for locating .winmd files. The runtime built-in WinRT interop support had methods like Also, I was wrong that |
Attempt at summary:
|
@andrew-boyarshin with the above reasons mentioned in the @steveharter's |
Closing, somehow the automation is not working for this PR |
Fixes #58319
Add a test WinMD file to prevent regressions. Had to be compiled with .NET Framework ILASM, since .NET ILASM silently ignores
/MDV
switch, which is necessary to produce WinMD that reproduces the crash (MetadataVersion
is used to determine the existence of virtual AssemblyRefs).