ILSpy icon indicating copy to clipboard operation
ILSpy copied to clipboard

Potential issue in GetDefinition() returning UnknownType

Open irsdl opened this issue 3 years ago • 4 comments

Steps to reproduce

  1. The following code runs just fine and resolve the type:
System.Reflection.Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.Net\assembly\GAC_64\Microsoft.AppV.AppvClientComConsumer\v4.0_10.0.0.0__31bf3856ad364e35\Microsoft.AppV.AppvClientComConsumer.dll").GetType(@"msclr.interop.context_node<char const \*\,System::String ^>")
  1. However, when running the following code, the result of GetDefinition() is null so I cannot get its MetadataToken and use DecompileAsString:
var mydecompiler = new ICSharpCode.Decompiler.CSharp.CSharpDecompiler(@"C:\WINDOWS\Microsoft.Net\assembly\GAC_64\Microsoft.AppV.AppvClientComConsumer\v4.0_10.0.0.0__31bf3856ad364e35\Microsoft.AppV.AppvClientComConsumer.dll", new ICSharpCode.Decompiler.DecompilerSettings() { });

var name = new ICSharpCode.Decompiler.TypeSystem.FullTypeName(@"msclr.interop.context_node<char const \*\,System::String ^>");

 var typeInfo = mydecompiler.TypeSystem.MainModule.Compilation.FindType(name).GetDefinition();

Console.WriteLine(typeInfo != null);

The problem seems to come from the following line of code which does not resolve the type: https://github.com/icsharpcode/ILSpy/blob/d2cc9e0989649451e4a6f4200bab5e84c3a24ba9/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs#L444

Details

Product in use: The ICSharpCode.Decompiler NuGet package Version in use: v7.2.1.6856 and ICSharpCode.Decompiler.8.0.0.7124-preview2

irsdl avatar Sep 04 '22 22:09 irsdl

Have you tried using the full type name without any escape sequences, e.g. @"msclr.interop.context_node<char const *,System::String ^>"?

This is how the name is specified in the metadata tables: image

As far as I know, the only special characters interpreted by the FullTypeName constructor are:

  • . for separating namespaces and types.
  • + for denoting nested types
  • ` for denoting type parameter counts

This is because the library is primarily targetted at C#.

@dgrunwald do you think it is necessary to add compatibility to the logic used here? https://github.com/dotnet/runtime/blob/e55c908229e36f99a52745d4ee85316a0e8bb6a2/src/mono/System.Private.CoreLib/src/System/TypeNameParser.cs#L256

siegfriedpammer avatar Sep 08 '22 19:09 siegfriedpammer

Have you tried using the full type name without any escape sequences, e.g. @"msclr.interop.context_node<char const *,System::String ^>"?

The code was completely automated so I took a snapshot of that and added an @ by mistake instead of removing the \ character. I will test again and report back but I think this works fine and it was my mistake :) I just need to figure out why the value in my program was escaped. Thank you.

irsdl avatar Sep 08 '22 21:09 irsdl

After all it seems to be a bug I think in ILSpy. It seems the way .NET handles it is different than ILSpy. The following screenshot shows how in .NET it escapes characters such as , but as they are not escaped in ILSpy, iteration will fail: image

In the example above, the cliext.Enum_iterator<System::Collections::IEnumerable\,System::Collections::IEnumerator\,System::Object ^> won't be found and we have to use cliext.Enum_iterator<System::Collections::IEnumerable,System::Collections::IEnumerator,System::Object ^>

In my code, the workaround was easy (t is a Type object):

var name = new FullTypeName(t.FullName.Replace(@"\",""));

irsdl avatar Sep 09 '22 00:09 irsdl

FullTypeName is just meant to split a string, it doesn't have any escaping logic. Parsing more complicated type names (like the TypeNameParser @siegfriedpammer linked) is handled in ReflectionHelper.ParseReflectionName -- that's where we should add support for \ escapes (I had no idea those existed).

dgrunwald avatar Sep 09 '22 14:09 dgrunwald