From 3fa128eb01a7c84f2b99727460705b2decf439fe Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 8 Jul 2023 14:33:24 +0200 Subject: [PATCH 1/6] Add typeref scope tests. --- .../MetadataResolverTest.cs | 68 +++++++-- .../Properties/Resources.Designer.cs | 21 +++ .../Properties/Resources.resx | 9 ++ .../Resources/TypeRefModuleScope.exe | Bin 0 -> 2048 bytes .../TypeRefNullScope_CurrentModule.exe | Bin 0 -> 2048 bytes .../TypeRefNullScope_ExportedType.exe | Bin 0 -> 2048 bytes .../TypeReferenceTest.cs | 143 +++++++++++++++++- .../DotNet/HelloWorld/HelloWorld.csproj | 4 + .../TestBinaries/DotNet/HelloWorld/Program.cs | 5 +- 9 files changed, 230 insertions(+), 20 deletions(-) create mode 100644 test/AsmResolver.DotNet.Tests/Resources/TypeRefModuleScope.exe create mode 100644 test/AsmResolver.DotNet.Tests/Resources/TypeRefNullScope_CurrentModule.exe create mode 100644 test/AsmResolver.DotNet.Tests/Resources/TypeRefNullScope_ExportedType.exe diff --git a/test/AsmResolver.DotNet.Tests/MetadataResolverTest.cs b/test/AsmResolver.DotNet.Tests/MetadataResolverTest.cs index 06d4d5ca7..e2dd55a28 100644 --- a/test/AsmResolver.DotNet.Tests/MetadataResolverTest.cs +++ b/test/AsmResolver.DotNet.Tests/MetadataResolverTest.cs @@ -4,6 +4,7 @@ using AsmResolver.DotNet.Signatures; using AsmResolver.DotNet.TestCases.NestedClasses; using AsmResolver.PE.DotNet.Cil; +using AsmResolver.PE.DotNet.Metadata.Tables; using Xunit; namespace AsmResolver.DotNet.Tests @@ -52,6 +53,7 @@ public void ResolveSystemObjectNetCore() var reference = new TypeReference(module.CorLibTypeFactory.CorLibScope, "System", "Object"); var definition = _coreResolver.ResolveType(reference); + Assert.NotNull(definition); Assert.True(definition.IsTypeOf(reference.Namespace, reference.Name)); } @@ -69,8 +71,8 @@ public void ResolveType() { var module = ModuleDefinition.FromFile(typeof(TopLevelClass1).Assembly.Location); - var topLevelClass1 = new TypeReference(new AssemblyReference(module.Assembly), - typeof(TopLevelClass1).Namespace, typeof(TopLevelClass1).Name); + var topLevelClass1 = new TypeReference(new AssemblyReference(module.Assembly!), + typeof(TopLevelClass1).Namespace, nameof(TopLevelClass1)); var definition = _coreResolver.ResolveType(topLevelClass1); Assert.Equal((ITypeDefOrRef) topLevelClass1, definition, _comparer); @@ -104,7 +106,7 @@ public void ResolveTypeReferenceThenChangeDefAndResolveAgain() ITypeDefOrRef expected = new TypeReference(module.CorLibTypeFactory.CorLibScope, "System", "Object"); var reference = new TypeReference(module.CorLibTypeFactory.CorLibScope, "System", "Object"); - var definition = _fwResolver.ResolveType(reference); + var definition = _fwResolver.ResolveType(reference)!; Assert.Equal(expected, definition, _comparer); definition.Name = "String"; Assert.NotEqual(expected, _fwResolver.ResolveType(reference), _comparer); @@ -115,9 +117,9 @@ public void ResolveNestedType() { var module = ModuleDefinition.FromFile(typeof(TopLevelClass1).Assembly.Location); - var topLevelClass1 = new TypeReference(new AssemblyReference(module.Assembly), - typeof(TopLevelClass1).Namespace, typeof(TopLevelClass1).Name); - var nested1 = new TypeReference(topLevelClass1,null, typeof(TopLevelClass1.Nested1).Name); + var topLevelClass1 = new TypeReference(new AssemblyReference(module.Assembly!), + typeof(TopLevelClass1).Namespace, nameof(TopLevelClass1)); + var nested1 = new TypeReference(topLevelClass1,null, nameof(TopLevelClass1.Nested1)); var definition = _coreResolver.ResolveType(nested1); @@ -129,16 +131,52 @@ public void ResolveNestedNestedType() { var module = ModuleDefinition.FromFile(typeof(TopLevelClass1).Assembly.Location); - var topLevelClass1 = new TypeReference(new AssemblyReference(module.Assembly), - typeof(TopLevelClass1).Namespace, typeof(TopLevelClass1).Name); - var nested1 = new TypeReference(topLevelClass1,null, typeof(TopLevelClass1.Nested1).Name); - var nested1nested1 = new TypeReference(nested1,null, typeof(TopLevelClass1.Nested1.Nested1Nested1).Name); + var topLevelClass1 = new TypeReference(new AssemblyReference(module.Assembly!), + typeof(TopLevelClass1).Namespace, nameof(TopLevelClass1)); + var nested1 = new TypeReference(topLevelClass1,null, nameof(TopLevelClass1.Nested1)); + var nested1nested1 = new TypeReference(nested1,null, nameof(TopLevelClass1.Nested1.Nested1Nested1)); var definition = _fwResolver.ResolveType(nested1nested1); Assert.Equal((ITypeDefOrRef) nested1nested1, definition, _comparer); } + [Fact] + public void ResolveTypeWithModuleScope() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefModuleScope); + var reference = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 2)); + + var definition = reference.Resolve(); + + Assert.NotNull(definition); + Assert.Same(module, definition.Module); + } + + [Fact] + public void ResolveTypeWithNullScopeCurrentModule() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefNullScope_CurrentModule); + var reference = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 2)); + + var definition = reference.Resolve(); + + Assert.NotNull(definition); + Assert.Same(module, definition.Module); + } + + [Fact] + public void ResolveTypeWithNullScopeExportedType() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefNullScope_ExportedType); + var reference = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 1)); + + var definition = reference.Resolve(); + + Assert.NotNull(definition); + Assert.Equal("mscorlib", definition.Module!.Assembly!.Name); + } + [Fact] public void ResolveConsoleWriteLineMethod() { @@ -187,13 +225,13 @@ public void ResolveExportedMemberReference() var resolver = (AssemblyResolverBase) module.MetadataResolver.AssemblyResolver; resolver.AddToCache(assembly1, assembly1); resolver.AddToCache(assembly2, assembly2); - resolver = (AssemblyResolverBase) assembly1.ManifestModule.MetadataResolver.AssemblyResolver; + resolver = (AssemblyResolverBase) assembly1.ManifestModule!.MetadataResolver.AssemblyResolver; resolver.AddToCache(assembly1, assembly1); resolver.AddToCache(assembly2, assembly2); // Resolve - var instructions = module.ManagedEntryPointMethod.CilMethodBody.Instructions; - Assert.NotNull(((IMethodDescriptor) instructions[0].Operand).Resolve()); + var instructions = module.ManagedEntryPointMethod!.CilMethodBody!.Instructions; + Assert.NotNull(((IMethodDescriptor) instructions[0].Operand!).Resolve()); } [Fact] @@ -208,10 +246,10 @@ public void MaliciousExportedTypeLoop() var resolver = (AssemblyResolverBase) module.MetadataResolver.AssemblyResolver; resolver.AddToCache(assembly1, assembly1); resolver.AddToCache(assembly2, assembly2); - resolver = (AssemblyResolverBase) assembly1.ManifestModule.MetadataResolver.AssemblyResolver; + resolver = (AssemblyResolverBase) assembly1.ManifestModule!.MetadataResolver.AssemblyResolver; resolver.AddToCache(assembly1, assembly1); resolver.AddToCache(assembly2, assembly2); - resolver = (AssemblyResolverBase) assembly2.ManifestModule.MetadataResolver.AssemblyResolver; + resolver = (AssemblyResolverBase) assembly2.ManifestModule!.MetadataResolver.AssemblyResolver; resolver.AddToCache(assembly1, assembly1); resolver.AddToCache(assembly2, assembly2); diff --git a/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs b/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs index e67584486..5f2f0400f 100644 --- a/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs +++ b/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs @@ -387,5 +387,26 @@ public static byte[] ArgListTest { return ((byte[])(obj)); } } + + public static byte[] TypeRefModuleScope { + get { + object obj = ResourceManager.GetObject("TypeRefModuleScope", resourceCulture); + return ((byte[])(obj)); + } + } + + public static byte[] TypeRefNullScope_CurrentModule { + get { + object obj = ResourceManager.GetObject("TypeRefNullScope_CurrentModule", resourceCulture); + return ((byte[])(obj)); + } + } + + public static byte[] TypeRefNullScope_ExportedType { + get { + object obj = ResourceManager.GetObject("TypeRefNullScope_ExportedType", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/test/AsmResolver.DotNet.Tests/Properties/Resources.resx b/test/AsmResolver.DotNet.Tests/Properties/Resources.resx index 8ebc736a8..5edb05e41 100644 --- a/test/AsmResolver.DotNet.Tests/Properties/Resources.resx +++ b/test/AsmResolver.DotNet.Tests/Properties/Resources.resx @@ -165,4 +165,13 @@ ..\Resources\ArgListTest.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\TypeRefModuleScope.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\TypeRefNullScope_CurrentModule.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\TypeRefNullScope_ExportedType.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + diff --git a/test/AsmResolver.DotNet.Tests/Resources/TypeRefModuleScope.exe b/test/AsmResolver.DotNet.Tests/Resources/TypeRefModuleScope.exe new file mode 100644 index 0000000000000000000000000000000000000000..e9d3163596fb48fa733bbec2dd761cd51619d9cd GIT binary patch literal 2048 zcmeHG&ubGw6#h0zLlSMR3euwJB&`q&F45#7sKm4-T9USqswf4MO@_L%Kf>--S`Xqy z(3>am>Phh|SUia*5&A#$=KtU&zBjvRf>Z@Bx%4sf-uHgY%=czz>-S$F4j@6Z*8_IQ zvXqtnyLv|HiF2PP@G-rc-O*~h*|mqJFS?$);k9hhZaIz{2tx{Q(-Ed47FHU|#&suyk`;@vM3KvVam<+dXZ z<)|jvuLv!LY5bq8QU5H=Erv041n@-zXz={)BntjRbe~pb^3+LY?rbbiPb)K5X)IMV zwPV=FuzV$lGkDTZP&9* z0}a=f%Pm{_-Bw#--gSJ}k}4XO?ib*$X9lunI+We^18Jk)G9Bpc!1b_VJd*7|)!y)Z zX&crypD2Eue*OLJ#rnHrU+c2-A;A}<#Ras~rzh)orb~M-6VS9XsO9YM|}e#{3pAYM@{7L{88M%FZ^eE2mk;8 literal 0 HcmV?d00001 diff --git a/test/AsmResolver.DotNet.Tests/Resources/TypeRefNullScope_CurrentModule.exe b/test/AsmResolver.DotNet.Tests/Resources/TypeRefNullScope_CurrentModule.exe new file mode 100644 index 0000000000000000000000000000000000000000..3ade50d67f118b8b33f91d7ec3042618c51b51f5 GIT binary patch literal 2048 zcmeHG&1(}u6#s3Kh9uhh1=6DEB&`q&F45#7sH|yAv?OgIt)djn*HBmXBkXRa^&nmZ zy?GL^o)pi5#gljvq5nf~{tsT_d$XG+NLBEXOCK}ye(!7M_hx5n_g^6nAVIU&19nKW z7;63d@{Gb0=RZ&2V|q8cqg8jas}D_IbUk;&YucjSbR0JjEh)TBN0^S7U#<(=?MQum zJTnt*y|MsQwHT0gUi44fLk>r@0s?X$jhs%7fS_s6w(+~$mSkZFWf-HyPqb2hVDtrZATo8 zC@0y^2sOEB{GY5+|18WchB0&m@I?b?@civ0a{fbfpQ>LfFJE|#aKm6 z$RsvPDzdJu&kSVMbSS#*2hv8ZX*$r`f$L$p^+>h@m3!0orQNc& z`B3rW%n&_aMM3o*So|M)@!+`^ul@mE;+xssCP?i;PlY~a-h1DBZ)UzXvs-=q76|}Jnw<`? zO;(Ai^}*^TrH9Ua9m1#dPIjABcCrtiT0Vc~$yKlJ@Mhh0WxyMPdu^9nE}xmNaYwd< zF*ukxA8oxb3shJikal0kr|lw#<1CLU3J*lVTRCz#O_QcloDAg^ZzZwC3IU2MNx*ys z4C~Rg5e!T4GYga>e_vyEIqaMNTaW{(o?MFXy&h}?Vm%QYvm%-JB9q8 zPZ)WlkS|=nt#(N2r}{|V_zPf!mOWB_E$}RN)mIg36rrxY&QvO!h} z9mMA7?zR;8#R?b=xl=suL0>B^-NV3{h!s#oo|-&KT8XMsnqh$}Zx}ZPa_kjv{h&HhmpyuY_)AM1;=kn&$b$vmaZ>tftqwgn8cE21)^fP z6x{Fw;hAEYY@q$U{N~z^%b!0a@2g*$B{*2> z%jWXp>51K~Bp4gRXs%1_s`7ak_j>VH0X&(O-t4;23^ZpUjFxSqa{=7!U2^0f&Kuz2 Qzj^1z;iP}W`u}d=H|2zF@&Et; literal 0 HcmV?d00001 diff --git a/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs b/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs index a0a5ae2e5..0c2618196 100644 --- a/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs +++ b/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using AsmResolver.DotNet.Signatures; using AsmResolver.DotNet.Signatures.Types; using AsmResolver.PE.DotNet.Metadata.Tables; @@ -15,15 +16,146 @@ public class TypeReferenceTest public void ReadAssemblyRefScope() { var module = ModuleDefinition.FromBytes(Properties.Resources.HelloWorld); - var typeRef = (TypeReference) module.LookupMember(new MetadataToken(TableIndex.TypeRef, 13)); - Assert.Equal("mscorlib", typeRef.Scope.Name); + var typeRef = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 13)); + + var scope = Assert.IsAssignableFrom(typeRef.Scope); + Assert.Equal("mscorlib", scope.Name); + } + + [Fact] + public void WriteAssemblyRefScope() + { + var module = new ModuleDefinition("SomeModule"); + module.GetOrCreateModuleType().Fields.Add(new FieldDefinition( + "SomeField", + FieldAttributes.Static, + new TypeDefOrRefSignature(new TypeReference( + new AssemblyReference("SomeAssembly", new Version(1, 0, 0, 0)), + "SomeNamespace", "SomeName") + ).ImportWith(module.DefaultImporter) + )); + + var image = module.ToPEImage(); + + var newModule = ModuleDefinition.FromImage(image); + var typeRef = newModule.GetOrCreateModuleType().Fields.First().Signature!.FieldType.GetUnderlyingTypeDefOrRef()!; + + var scope = Assert.IsAssignableFrom(typeRef.Scope); + Assert.Equal("SomeAssembly", scope.Name); + } + + [Fact] + public void ReadTypeRefScope() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.HelloWorld); + var typeRef = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 4)); + + var scope = Assert.IsAssignableFrom(typeRef.Scope); + Assert.Equal("DebuggableAttribute", scope.Name); + } + + [Fact] + public void WriteTypeRefScope() + { + var module = new ModuleDefinition("SomeModule"); + module.GetOrCreateModuleType().Fields.Add(new FieldDefinition( + "SomeField", + FieldAttributes.Static, + new TypeDefOrRefSignature(new TypeReference( + new TypeReference( + new AssemblyReference("SomeAssembly", new Version(1, 0, 0, 0)), + "SomeNamespace", "SomeName"), + null, + "SomeNestedType" + )).ImportWith(module.DefaultImporter) + )); + + var image = module.ToPEImage(); + + var newModule = ModuleDefinition.FromImage(image); + var typeRef = newModule.GetOrCreateModuleType().Fields.First().Signature!.FieldType.GetUnderlyingTypeDefOrRef()!; + + var scope = Assert.IsAssignableFrom(typeRef.Scope); + Assert.Equal("SomeName", scope.Name); + } + + [Fact] + public void ReadModuleScope() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefModuleScope); + var typeRef = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 2)); + + var scope = Assert.IsAssignableFrom(typeRef.Scope); + Assert.Same(module, scope); + } + + [Fact] + public void WriteModuleScope() + { + var module = new ModuleDefinition("SomeModule"); + module.GetOrCreateModuleType().Fields.Add(new FieldDefinition( + "SomeField", + FieldAttributes.Static, + new TypeDefOrRefSignature(new TypeReference( + module, + "SomeNamepace", "SomeName") + ).ImportWith(module.DefaultImporter) + )); + + var image = module.ToPEImage(); + + var newModule = ModuleDefinition.FromImage(image); + var typeRef = newModule.GetOrCreateModuleType().Fields.First().Signature!.FieldType.GetUnderlyingTypeDefOrRef()!; + + var scope = Assert.IsAssignableFrom(typeRef.Scope); + Assert.Equal(module.Name, scope.Name); + } + + [Fact] + public void WriteNullScope() + { + var module = new ModuleDefinition("SomeModule"); + module.GetOrCreateModuleType().Fields.Add(new FieldDefinition( + "SomeField", + FieldAttributes.Static, + new TypeDefOrRefSignature(new TypeReference( + null, + "SomeNamespace", "SomeName") + ).ImportWith(module.DefaultImporter) + )); + + var image = module.ToPEImage(); + + var newModule = ModuleDefinition.FromImage(image); + var typeRef = newModule.GetOrCreateModuleType().Fields.First().Signature!.FieldType.GetUnderlyingTypeDefOrRef()!; + + Assert.Null(typeRef.Scope); + } + + [Fact] + public void ReadNullScopeCurrentModule() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefNullScope_CurrentModule); + var typeRef = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 2)); + + Assert.Null(typeRef.Scope); + } + + [Fact] + public void ReadNullScopeExportedType() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefNullScope_ExportedType); + var typeRef = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 1)); + + Assert.Null(typeRef.Scope); } [Fact] public void ReadName() { var module = ModuleDefinition.FromBytes(Properties.Resources.HelloWorld); - var typeRef = (TypeReference) module.LookupMember(new MetadataToken(TableIndex.TypeRef, 13)); + var typeRef = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 13)); + Assert.Equal("Console", typeRef.Name); } @@ -31,7 +163,8 @@ public void ReadName() public void ReadNamespace() { var module = ModuleDefinition.FromBytes(Properties.Resources.HelloWorld); - var typeRef = (TypeReference) module.LookupMember(new MetadataToken(TableIndex.TypeRef, 13)); + var typeRef = module.LookupMember(new MetadataToken(TableIndex.TypeRef, 13)); + Assert.Equal("System", typeRef.Namespace); } @@ -41,6 +174,7 @@ public void CorLibTypeToTypeSignatureShouldReturnCorLibTypeSignature() var module = new ModuleDefinition("SomeModule"); var reference = new TypeReference(module, module.CorLibTypeFactory.CorLibScope, "System", "Object"); var signature = Assert.IsAssignableFrom(reference.ToTypeSignature()); + Assert.Equal(ElementType.Object, signature.ElementType); } @@ -50,6 +184,7 @@ public void NonCorLibTypeToTypeSignatureShouldReturnTypeDefOrRef() var module = new ModuleDefinition("SomeModule"); var reference = new TypeReference(module, module.CorLibTypeFactory.CorLibScope, "System", "Array"); var signature = Assert.IsAssignableFrom(reference.ToTypeSignature()); + Assert.Equal(signature.Type, reference, Comparer); } } diff --git a/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj b/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj index 329c82d3e..53d2dbb55 100644 --- a/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj +++ b/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj @@ -9,6 +9,10 @@ AnyCPU + + + none + diff --git a/test/TestBinaries/DotNet/HelloWorld/Program.cs b/test/TestBinaries/DotNet/HelloWorld/Program.cs index 575ec4cc4..c16dc7682 100644 --- a/test/TestBinaries/DotNet/HelloWorld/Program.cs +++ b/test/TestBinaries/DotNet/HelloWorld/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; namespace HelloWorld { @@ -6,7 +7,9 @@ public class Program { private static void Main(string[] args) { - Console.WriteLine("Hello, World!"); + var list = args.ToList(); + foreach (var item in list) + Console.WriteLine(item); } } } From b36fda7d07315ce995c9cd73e363d8a1af49937a Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 8 Jul 2023 14:37:20 +0200 Subject: [PATCH 2/6] BUGFIX: Read null scope. If scope is a module, force-reference module row 1. --- .../Builder/DotNetDirectoryBuffer.CodedIndices.cs | 2 +- src/AsmResolver.DotNet/Serialized/SerializedTypeReference.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuffer.CodedIndices.cs b/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuffer.CodedIndices.cs index 52e6c3df8..09a9f3afa 100644 --- a/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuffer.CodedIndices.cs +++ b/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuffer.CodedIndices.cs @@ -41,7 +41,7 @@ private uint AddResolutionScope(IResolutionScope? scope, bool allowDuplicates, b TableIndex.AssemblyRef => AddAssemblyReference(scope as AssemblyReference, allowDuplicates, preserveRid), TableIndex.TypeRef => AddTypeReference(scope as TypeReference, allowDuplicates, preserveRid), TableIndex.ModuleRef => AddModuleReference(scope as ModuleReference, allowDuplicates, preserveRid), - TableIndex.Module => 0, + TableIndex.Module => new MetadataToken(TableIndex.Module, 1), _ => throw new ArgumentOutOfRangeException(nameof(scope)) }; diff --git a/src/AsmResolver.DotNet/Serialized/SerializedTypeReference.cs b/src/AsmResolver.DotNet/Serialized/SerializedTypeReference.cs index 4e0cb839b..75bf2122a 100644 --- a/src/AsmResolver.DotNet/Serialized/SerializedTypeReference.cs +++ b/src/AsmResolver.DotNet/Serialized/SerializedTypeReference.cs @@ -41,7 +41,7 @@ public SerializedTypeReference(ModuleReaderContext context, MetadataToken token, protected override IResolutionScope? GetScope() { if (_row.ResolutionScope == 0) - return _context.ParentModule; + return null; var tablesStream = _context.TablesStream; var decoder = tablesStream.GetIndexEncoder(CodedIndex.ResolutionScope); From 9ee3ba2549968bded774c52d6deed86caa4528dd Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 8 Jul 2023 14:48:50 +0200 Subject: [PATCH 3/6] BUGFIX: Allow for typerefs with null scopes to be imported. --- src/AsmResolver.DotNet/ReferenceImporter.cs | 33 ++++++++++--------- .../TypeReferenceTest.cs | 12 ++++--- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/AsmResolver.DotNet/ReferenceImporter.cs b/src/AsmResolver.DotNet/ReferenceImporter.cs index 1f0821c10..c9c2b26c7 100644 --- a/src/AsmResolver.DotNet/ReferenceImporter.cs +++ b/src/AsmResolver.DotNet/ReferenceImporter.cs @@ -30,20 +30,12 @@ public ModuleDefinition TargetModule get; } - private static void AssertTypeIsValid(ITypeDefOrRef? type) - { - if (type is null) - throw new ArgumentNullException(nameof(type)); - if (type.Scope is null) - throw new ArgumentException("Cannot import types that are not added to a module."); - } - /// /// Imports a resolution scope. /// /// The resolution scope to import. /// The imported resolution scope. - public IResolutionScope ImportScope(IResolutionScope? scope) + public IResolutionScope ImportScope(IResolutionScope scope) { if (scope is null) throw new ArgumentNullException(nameof(scope)); @@ -181,14 +173,16 @@ public ITypeDefOrRef ImportType(ITypeDefOrRef type) /// The imported type. protected virtual ITypeDefOrRef ImportType(TypeDefinition type) { - AssertTypeIsValid(type); - + if (type is null) + throw new ArgumentNullException(nameof(type)); if (type.IsImportedInModule(TargetModule)) return type; + if (((ITypeDescriptor) type).Scope is not { } scope) + throw new ArgumentException("Cannot import a type that has not been added to a module."); return new TypeReference( TargetModule, - ImportScope(((ITypeDescriptor) type).Scope), + ImportScope(scope), type.Namespace, type.Name); } @@ -200,12 +194,18 @@ protected virtual ITypeDefOrRef ImportType(TypeDefinition type) /// The imported type. protected virtual ITypeDefOrRef ImportType(TypeReference type) { - AssertTypeIsValid(type); - + if (type is null) + throw new ArgumentNullException(nameof(type)); if (type.IsImportedInModule(TargetModule)) return type; - return new TypeReference(TargetModule, ImportScope(type.Scope!), type.Namespace, type.Name); + return new TypeReference( + TargetModule, + type.Scope is not null + ? ImportScope(type.Scope) + : null, + type.Namespace, + type.Name); } /// @@ -215,7 +215,8 @@ protected virtual ITypeDefOrRef ImportType(TypeReference type) /// The imported type. protected virtual ITypeDefOrRef ImportType(TypeSpecification type) { - AssertTypeIsValid(type); + if (type is null) + throw new ArgumentNullException(nameof(type)); if (type.Signature is null) throw new ArgumentNullException(nameof(type)); diff --git a/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs b/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs index 0c2618196..002801db9 100644 --- a/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs +++ b/test/AsmResolver.DotNet.Tests/TypeReferenceTest.cs @@ -31,7 +31,8 @@ public void WriteAssemblyRefScope() FieldAttributes.Static, new TypeDefOrRefSignature(new TypeReference( new AssemblyReference("SomeAssembly", new Version(1, 0, 0, 0)), - "SomeNamespace", "SomeName") + "SomeNamespace", + "SomeName") ).ImportWith(module.DefaultImporter) )); @@ -64,7 +65,8 @@ public void WriteTypeRefScope() new TypeDefOrRefSignature(new TypeReference( new TypeReference( new AssemblyReference("SomeAssembly", new Version(1, 0, 0, 0)), - "SomeNamespace", "SomeName"), + "SomeNamespace", + "SomeName"), null, "SomeNestedType" )).ImportWith(module.DefaultImporter) @@ -98,7 +100,8 @@ public void WriteModuleScope() FieldAttributes.Static, new TypeDefOrRefSignature(new TypeReference( module, - "SomeNamepace", "SomeName") + "SomeNamepace", + "SomeName") ).ImportWith(module.DefaultImporter) )); @@ -120,7 +123,8 @@ public void WriteNullScope() FieldAttributes.Static, new TypeDefOrRefSignature(new TypeReference( null, - "SomeNamespace", "SomeName") + "SomeNamespace", + "SomeName") ).ImportWith(module.DefaultImporter) )); From 07539155208731e7c276a5346b20e6d5736efa54 Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 8 Jul 2023 14:51:19 +0200 Subject: [PATCH 4/6] BUGFIX: Default to parent module if the to-be-resolved typeref's scope is null. --- .../DefaultMetadataResolver.cs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs index 0d625ed02..e80d5cae4 100644 --- a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs +++ b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs @@ -166,8 +166,11 @@ public TypeResolution(IAssemblyResolver resolver) public TypeDefinition? ResolveTypeReference(TypeReference? reference) { - var scope = reference?.Scope; - if (reference?.Name is null || scope is null || _scopeStack.Contains(scope)) + if (reference is null) + return null; + + var scope = reference.Scope ?? reference.Module; + if (reference.Name is null || scope is null || _scopeStack.Contains(scope)) return null; _scopeStack.Push(scope); @@ -241,13 +244,6 @@ public TypeResolution(IAssemblyResolver resolver) private TypeDefinition? FindTypeInModule(ModuleDefinition module, Utf8String? ns, Utf8String name) { - for (int i = 0; i < module.ExportedTypes.Count; i++) - { - var exportedType = module.ExportedTypes[i]; - if (exportedType.IsTypeOfUtf8(ns, name)) - return ResolveExportedType(exportedType); - } - for (int i = 0; i < module.TopLevelTypes.Count; i++) { var type = module.TopLevelTypes[i]; @@ -255,6 +251,13 @@ public TypeResolution(IAssemblyResolver resolver) return type; } + for (int i = 0; i < module.ExportedTypes.Count; i++) + { + var exportedType = module.ExportedTypes[i]; + if (exportedType.IsTypeOfUtf8(ns, name)) + return ResolveExportedType(exportedType); + } + return null; } From a3864361012d21bbff1f9edbde89d9567742457b Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 8 Jul 2023 14:59:00 +0200 Subject: [PATCH 5/6] Add sanity tests in typesig for new nullable scopes. --- .../Signatures/TypeSignatureTest.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/AsmResolver.DotNet.Tests/Signatures/TypeSignatureTest.cs b/test/AsmResolver.DotNet.Tests/Signatures/TypeSignatureTest.cs index 5c26a3518..d3afe8f78 100644 --- a/test/AsmResolver.DotNet.Tests/Signatures/TypeSignatureTest.cs +++ b/test/AsmResolver.DotNet.Tests/Signatures/TypeSignatureTest.cs @@ -4,6 +4,7 @@ using AsmResolver.DotNet.Signatures.Types; using AsmResolver.DotNet.TestCases.Generics; using AsmResolver.DotNet.TestCases.Types; +using AsmResolver.PE.DotNet.Metadata.Tables; using AsmResolver.PE.DotNet.Metadata.Tables.Rows; using Xunit; @@ -619,5 +620,38 @@ public void IgnorePinnedModifiers() Assert.True(type1.IsCompatibleWith(type2)); Assert.True(type2.IsCompatibleWith(type1)); } + + [Fact] + public void GetModuleOfTypeDefOrRef() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.HelloWorld); + var signature = module.GetOrCreateModuleType().ToTypeSignature(); + Assert.Same(module, signature.Module); + } + + [Fact] + public void GetModuleOfTypeDefOrRefWithNullScope() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefNullScope_CurrentModule); + var signature = module + .LookupMember(new MetadataToken(TableIndex.TypeRef, 2)) + .ToTypeSignature(); + + Assert.Null(signature.Scope); + Assert.Same(module, signature.Module); + } + + [Fact] + public void GetModuleOfSpecificationTypeWithNullScope() + { + var module = ModuleDefinition.FromBytes(Properties.Resources.TypeRefNullScope_CurrentModule); + var signature = module + .LookupMember(new MetadataToken(TableIndex.TypeRef, 2)) + .ToTypeSignature() + .MakeSzArrayType(); + + Assert.Null(signature.Scope); + Assert.Same(module, signature.Module); + } } } From 21bfdf4618e7493b7d5830ad4e9b45fc2dcc33ce Mon Sep 17 00:00:00 2001 From: Washi Date: Fri, 14 Jul 2023 14:43:55 +0200 Subject: [PATCH 6/6] Revert hw changes. --- test/TestBinaries/DotNet/HelloWorld/Program.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/TestBinaries/DotNet/HelloWorld/Program.cs b/test/TestBinaries/DotNet/HelloWorld/Program.cs index c16dc7682..6159d9786 100644 --- a/test/TestBinaries/DotNet/HelloWorld/Program.cs +++ b/test/TestBinaries/DotNet/HelloWorld/Program.cs @@ -7,9 +7,7 @@ public class Program { private static void Main(string[] args) { - var list = args.ToList(); - foreach (var item in list) - Console.WriteLine(item); + Console.WriteLine("Hello, World!"); } } }