Skip to content
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

CorLibType not perserved after TokenAllocator #252

Closed
JPaja opened this issue Feb 17, 2022 · 1 comment · Fixed by #253
Closed

CorLibType not perserved after TokenAllocator #252

JPaja opened this issue Feb 17, 2022 · 1 comment · Fixed by #253
Labels
bug dotnet Issues related to AsmResolver.DotNet
Milestone

Comments

@JPaja
Copy link
Contributor

JPaja commented Feb 17, 2022

Describe the bug

TypeReferences that are constructed by importing reflection type, are not preserved after using TokenAllocator on them.

Issue is same for allocating tokens on references generated by CorLibFactory where assembly contains typeof() of that type

To Reproduce

using AsmResolver.DotNet;
using AsmResolver.DotNet.Builder;

var module = ModuleDefinition.FromModule(typeof(Program).Module);

var importer = new ReferenceImporter(module);
var reference  = (TypeReference)importer.ImportType(typeof(int));
var reference2 = (TypeReference)importer.ImportType(typeof(void));

module.TokenAllocator.AssignNextAvailableToken(reference);
module.TokenAllocator.AssignNextAvailableToken(reference2);

var image = module.ToPEImage(new ManagedPEImageBuilder(MetadataBuilderFlags.PreserveAll));
var newModule = ModuleDefinition.FromImage(image);

var newReference = (TypeReference) newModule.LookupMember(reference.MetadataToken);
var newReference2 = (TypeReference) newModule.LookupMember(reference2.MetadataToken);

Assert.Equal(reference.Namespace, newReference.Namespace);
Assert.Equal(reference.Name, newReference.Name);
Assert.Equal(reference2.Namespace, newReference2.Namespace);
Assert.Equal(reference2.Name, newReference2.Name);
using AsmResolver.DotNet;
using AsmResolver.DotNet.Builder;
 
var module = ModuleDefinition.FromModule(typeof(Program).Module);

Type oldRef1 = typeof(int);
Type oldRef2 = typeof(void);

var reference  = (TypeReference)module.CorLibTypeFactory.Int32.ToTypeDefOrRef();
var reference2 = (TypeReference)module.CorLibTypeFactory.Void.ToTypeDefOrRef();

module.TokenAllocator.AssignNextAvailableToken(reference);
module.TokenAllocator.AssignNextAvailableToken(reference2);

var image = module.ToPEImage(new ManagedPEImageBuilder(MetadataBuilderFlags.PreserveAll));
var newModule = ModuleDefinition.FromImage(image);

var newReference = (TypeReference) newModule.LookupMember(reference.MetadataToken);
var newReference2 = (TypeReference) newModule.LookupMember(reference2.MetadataToken);

Assert.Equal(reference.Namespace, newReference.Namespace);
Assert.Equal(reference.Name, newReference.Name);
Assert.Equal(reference2.Namespace, newReference2.Namespace);
Assert.Equal(reference2.Name, newReference2.Name);

Expected behavior

newModule.LookupMember should not throw, and should return perserved TypeReference

Platform

  • OS:Windows 10
  • AsmResolver Version: 4.8 (nuget)
@JPaja JPaja added the bug label Feb 17, 2022
@JPaja JPaja changed the title Reflection imprted TypeReference not perserved after TokenAllocator CorLibTypes not perserved after TokenAllocator Feb 17, 2022
@JPaja JPaja changed the title CorLibTypes not perserved after TokenAllocator Type Void not perserved after TokenAllocator Feb 17, 2022
@JPaja JPaja changed the title Type Void not perserved after TokenAllocator CorLibType not perserved after TokenAllocator Feb 17, 2022
@JPaja
Copy link
Contributor Author

JPaja commented Feb 17, 2022

Update:

Seems like this is issue persists on any type, not just CorLibTypes.
And its not limited to typeof(), any code that can generate same TypeReference in compile time can cause same issue (for eg using type in locals, arguments, return types etc..).

Example:

using AsmResolver.DotNet;
using AsmResolver.DotNet.Builder;
 
var module = ModuleDefinition.FromModule(typeof(Program).Module);
var asmResRef = module.AssemblyReferences.First(a => a.Name == "AsmResolver.DotNet");
    
Type oldRef1 = typeof(MethodDefinition);
Type oldRef2 = typeof(ModuleDefinition);

var reference  = new TypeReference(module, asmResRef, "AsmResolver.DotNet", "MethodDefinition");
var reference2 = new TypeReference(module, asmResRef, "AsmResolver.DotNet", "ModuleDefinition");

module.TokenAllocator.AssignNextAvailableToken(reference);
module.TokenAllocator.AssignNextAvailableToken(reference2);

var image = module.ToPEImage(new ManagedPEImageBuilder(MetadataBuilderFlags.PreserveAll));
var newModule = ModuleDefinition.FromImage(image);

var newReference = (TypeReference) newModule.LookupMember(reference.MetadataToken);
var newReference2 = (TypeReference) newModule.LookupMember(reference2.MetadataToken);

Assert.Equal(reference.Namespace, newReference.Namespace);
Assert.Equal(reference.Name, newReference.Name);
Assert.Equal(reference2.Namespace, newReference2.Namespace);
Assert.Equal(reference2.Name, newReference2.Name);
using AsmResolver.DotNet;
using AsmResolver.DotNet.Builder;
 
var module = ModuleDefinition.FromModule(typeof(Program).Module);
var asmResRef = module.AssemblyReferences.First(a => a.Name == "AsmResolver.DotNet");

MethodDefinition oldRef1;
MethodDefinition oldRef2;

var reference  = new TypeReference(module, asmResRef, "AsmResolver.DotNet", "MethodDefinition");
var reference2 = new TypeReference(module, asmResRef, "AsmResolver.DotNet", "ModuleDefinition");

module.TokenAllocator.AssignNextAvailableToken(reference);
module.TokenAllocator.AssignNextAvailableToken(reference2);

var image = module.ToPEImage(new ManagedPEImageBuilder(MetadataBuilderFlags.PreserveAll));
var newModule = ModuleDefinition.FromImage(image);

var newReference = (TypeReference) newModule.LookupMember(reference.MetadataToken);
var newReference2 = (TypeReference) newModule.LookupMember(reference2.MetadataToken);

My initial guess is that adding same type reference with different token to metadata table gets ignored.

Possible solutions:

  • Allow duplicate type references in Metadata table
  • TokenAllocator.AssignNextToken should assign old token if it finds same instance in md table (Which would cause multiple TypeReference instances with same mdtoken)

@Washi1337 Washi1337 added the dotnet Issues related to AsmResolver.DotNet label Feb 18, 2022
@Washi1337 Washi1337 added this to the 4.9.0 milestone Feb 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug dotnet Issues related to AsmResolver.DotNet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants