Skip to content

Commit

Permalink
Fix exception on out-of-range tokens
Browse files Browse the repository at this point in the history
Throw ArgumentOutOfRangeException on out-of-range tokens when resolving members, instead of BadImageFormatException that SRM uses by default.

Issue: #121
  • Loading branch information
MSDN-WhiteKnight committed Apr 1, 2023
1 parent c32d9e2 commit 01e4b32
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
18 changes: 18 additions & 0 deletions CilTools.Metadata/MetadataAssembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,21 @@ public override Module ManifestModule
}
}

void ThrowIfOutOfRange(EntityHandle eh)
{
TableIndex ti;

if (MetadataTokens.TryGetTableIndex(eh.Kind, out ti))
{
int rowCount = this.reader.GetTableRowCount(ti);
int rowNumber = MetadataTokens.GetRowNumber(eh);

// Throw ArgumentOutOfRangeException to mirror Module.ResolveX behaviour.
// MetadataReader throws misleading BadImageFormatException in this case.
if (rowNumber > rowCount) throw new ArgumentOutOfRangeException("metadataToken");
}
}

Type ResolveTypeImpl(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
{
if (this.reader == null) return null;
Expand All @@ -215,6 +230,7 @@ Type ResolveTypeImpl(int metadataToken, Type[] genericTypeArguments, Type[] gene

if (eh.IsNil) return null;

ThrowIfOutOfRange(eh);
Type ret;

if (genericTypeArguments == null && genericMethodArguments == null)
Expand Down Expand Up @@ -282,6 +298,7 @@ MethodBase ResolveMethodImpl(int metadataToken, Type[] genericTypeArguments, Typ

if (eh.IsNil) return null;

ThrowIfOutOfRange(eh);
MethodBase m = null;

if (genericTypeArguments == null && genericMethodArguments == null)
Expand Down Expand Up @@ -346,6 +363,7 @@ FieldInfo ResolveFieldImpl(int metadataToken, Type[] genericTypeArguments, Type[
EntityHandle eh = MetadataTokens.EntityHandle(metadataToken);
if (eh.IsNil) return null;

ThrowIfOutOfRange(eh);
MethodBase declaringMethod = null;
FieldInfo ret;

Expand Down
62 changes: 62 additions & 0 deletions tests/CilTools.Metadata.Tests/MetadataAssemblyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,67 @@ public void Test_CorFlags()

Assert.AreEqual(0x0001, subsystem); //ILONLY
}

[TestMethod]
public void Test_ResolveMethod()
{
AssemblyReader reader = ReaderFactory.GetReader();
Assembly ass = reader.LoadFrom(typeof(SampleMethods).Assembly.Location);
ITokenResolver resolver = (ITokenResolver)ass;

MethodInfo mi = typeof(SampleMethods).GetMethod("PrintHelloWorld");

//valid
MethodBase miResolved = resolver.ResolveMethod(mi.MetadataToken);
Assert.AreEqual(mi.Name, miResolved.Name);
Assert.AreEqual(mi.MetadataToken, miResolved.MetadataToken);

//invalid
Assert.IsNull(resolver.ResolveMethod(0));
Assert.IsNull(resolver.ResolveMethod(0x4000001)); //Field
AssertThat.Throws<ArgumentOutOfRangeException>(() => resolver.ResolveMethod(0x6FFFFFF)); //MethodDef
AssertThat.Throws<ArgumentOutOfRangeException>(() => resolver.ResolveMethod(0xAFFFFFF)); //MemberRef
}

[TestMethod]
public void Test_ResolveField()
{
AssemblyReader reader = ReaderFactory.GetReader();
Assembly ass = reader.LoadFrom(typeof(SampleMethods).Assembly.Location);
ITokenResolver resolver = (ITokenResolver)ass;

FieldInfo fi = typeof(SampleMethods).GetField("Foo");

//valid
FieldInfo fiResolved = resolver.ResolveField(fi.MetadataToken);
Assert.AreEqual(fi.Name, fiResolved.Name);
Assert.AreEqual(fi.MetadataToken, fiResolved.MetadataToken);

//invalid
Assert.IsNull(resolver.ResolveField(0));
Assert.IsNull(resolver.ResolveField(0x6000001)); //MethodDef
AssertThat.Throws<ArgumentOutOfRangeException>(() => resolver.ResolveField(0x4FFFFFF)); //Field
AssertThat.Throws<ArgumentOutOfRangeException>(() => resolver.ResolveField(0xAFFFFFF)); //MemberRef
}

[TestMethod]
public void Test_ResolveType()
{
AssemblyReader reader = ReaderFactory.GetReader();
Assembly ass = reader.LoadFrom(typeof(SampleMethods).Assembly.Location);
ITokenResolver resolver = (ITokenResolver)ass;

//valid
Type tResolved = resolver.ResolveType(typeof(SampleMethods).MetadataToken);
Assert.AreEqual(typeof(SampleMethods).FullName, tResolved.FullName);
Assert.AreEqual(typeof(SampleMethods).MetadataToken, tResolved.MetadataToken);

//invalid
Assert.IsNull(resolver.ResolveType(0));
Assert.IsNull(resolver.ResolveType(0x6000001)); //MethodDef
AssertThat.Throws<ArgumentOutOfRangeException>(() => resolver.ResolveType(0x2FFFFFF)); //TypeDef
AssertThat.Throws<ArgumentOutOfRangeException>(() => resolver.ResolveType(0x1FFFFFF)); //TypeRef
AssertThat.Throws<ArgumentOutOfRangeException>(() => resolver.ResolveType(0x1BFFFFFF)); //TypeSpec
}
}
}

0 comments on commit 01e4b32

Please sign in to comment.