Browse Source

#1682, #1949 and #2394: Added basic algorithm of IsInterfaceImplementationRuntimeHelper

custom-signature-decoder-comparer
Siegfried Pammer 4 years ago
parent
commit
10664c8e75
  1. 42
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/MemberTests.cs
  2. 132
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  3. 59
      ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs

42
ICSharpCode.Decompiler.Tests/TestCases/Pretty/MemberTests.cs

@ -24,19 +24,57 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -24,19 +24,57 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class MemberTests
{
#if CS72
public interface IC
{
int MMM(in int x);
}
public class C : IC
{
public int MMM(in int x)
{
return x;
}
}
public interface IC2
{
object MMM(in object x);
int MMM2(ref int x);
}
public class C2 : IC2
{
public object MMM(in dynamic x)
{
return x;
}
public int MMM2(in int x)
{
return x;
}
int IC2.MMM2(ref int x)
{
return MMM2(in x);
}
}
#endif
public class IndexerNonDefaultName
{
[IndexerName("Foo")]
#if ROSLYN
public int this[int index] => 0;
#else
#pragma warning disable format
#pragma warning disable format
public int this[int index] {
get {
return 0;
}
}
#pragma warning restore format
#pragma warning restore format
#endif
}

132
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -22,6 +22,7 @@ using System.Diagnostics; @@ -22,6 +22,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Text.RegularExpressions;
using System.Threading;
@ -284,6 +285,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -284,6 +285,8 @@ namespace ICSharpCode.Decompiler.CSharp
var methodSemantics = module.MethodSemanticsLookup.GetSemantics(methodHandle).Item2;
if (methodSemantics != 0 && methodSemantics != System.Reflection.MethodSemanticsAttributes.Other)
return true;
if (IsInterfaceImplementationRuntimeHelper(module, methodHandle, methodSemantics))
return true;
if (settings.LocalFunctions && LocalFunctionDecompiler.IsLocalFunctionMethod(module, methodHandle))
return true;
if (settings.AnonymousMethods && methodHandle.HasGeneratedName(metadata) && methodHandle.IsCompilerGenerated(metadata))
@ -376,6 +379,135 @@ namespace ICSharpCode.Decompiler.CSharp @@ -376,6 +379,135 @@ namespace ICSharpCode.Decompiler.CSharp
return false;
}
static bool IsInterfaceImplementationRuntimeHelper(PEFile module, MethodDefinitionHandle handle, System.Reflection.MethodSemanticsAttributes methodSemantics)
{
var metadata = module.Metadata;
var method = metadata.GetMethodDefinition(handle);
if ((method.Attributes & System.Reflection.MethodAttributes.Static) != 0)
return false;
string rawName = metadata.GetString(method.Name);
int dot = rawName.LastIndexOf('.');
if (dot < 0)
return false;
string name = rawName.Substring(dot + 1);
if (handle.GetMethodImplementations(metadata).Length == 0)
return false;
if (method.RelativeVirtualAddress == 0)
return false;
var signature = metadata.GetBlobReader(method.Signature);
(int genericParameterCount, int parameterCount) = SignatureBlobComparer.ReadParameterCount(ref signature);
if (genericParameterCount == -1 || parameterCount == -1)
return false;
signature.Reset();
int maximumMethodSize = 4 * (parameterCount + 1) + 5 + 1;
var body = module.Reader.GetMethodBody(method.RelativeVirtualAddress);
var reader = body.GetILReader();
if (reader.RemainingBytes > maximumMethodSize)
return false;
for (int i = 0; i < parameterCount + 1; i++)
{
int index;
switch (reader.DecodeOpCode())
{
case ILOpCode.Ldarg:
index = reader.ReadUInt16();
if (index != i)
return false;
break;
case ILOpCode.Ldarg_s:
index = reader.ReadByte();
if (index != i)
return false;
break;
case ILOpCode.Ldarg_0:
if (i != 0)
return false;
break;
case ILOpCode.Ldarg_1:
if (i != 1)
return false;
break;
case ILOpCode.Ldarg_2:
if (i != 2)
return false;
break;
case ILOpCode.Ldarg_3:
if (i != 3)
return false;
break;
default:
return false;
}
}
if (reader.DecodeOpCode() != ILOpCode.Call)
return false;
EntityHandle targetHandle = MetadataTokenHelpers.EntityHandleOrNil(reader.ReadInt32());
if (targetHandle.IsNil)
return false;
if (reader.DecodeOpCode() != ILOpCode.Ret)
return false;
if (reader.RemainingBytes != 0)
return false;
BlobReader signature2;
string otherName;
switch (targetHandle.Kind)
{
case HandleKind.MethodDefinition:
if (genericParameterCount != 0)
return false;
var methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)targetHandle);
signature2 = metadata.GetBlobReader(methodDef.Signature);
otherName = metadata.GetString(methodDef.Name);
break;
case HandleKind.MethodSpecification:
if (genericParameterCount == 0)
return false;
var methodSpec = metadata.GetMethodSpecification((MethodSpecificationHandle)targetHandle);
var instantiation = methodSpec.DecodeSignature(MetadataExtensions.MinimalSignatureTypeProvider, default);
switch (methodSpec.Method.Kind)
{
case HandleKind.MethodDefinition:
var methodSpecDef = metadata.GetMethodDefinition((MethodDefinitionHandle)methodSpec.Method);
signature2 = metadata.GetBlobReader(methodSpecDef.Signature);
otherName = metadata.GetString(methodSpecDef.Name);
break;
case HandleKind.MemberReference:
var methodSpecRef = metadata.GetMemberReference((MemberReferenceHandle)methodSpec.Method);
if (methodSpecRef.GetKind() != MemberReferenceKind.Method)
return false;
signature2 = metadata.GetBlobReader(methodSpecRef.Signature);
otherName = metadata.GetString(methodSpecRef.Name);
break;
default:
return false;
}
break;
case HandleKind.MemberReference:
var methodRef = metadata.GetMemberReference((MemberReferenceHandle)targetHandle);
if (methodRef.GetKind() != MemberReferenceKind.Method)
return false;
signature2 = metadata.GetBlobReader(methodRef.Signature);
otherName = metadata.GetString(methodRef.Name);
break;
default:
return false;
}
if (otherName != name)
return false;
return SignatureBlobComparer.EqualsMethodSignature(signature, signature2, metadata, metadata);
}
static bool IsSwitchOnStringCache(SRM.FieldDefinition field, MetadataReader metadata)
{
return metadata.GetString(field.Name).StartsWith("<>f__switch", StringComparison.Ordinal);

59
ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs

@ -22,12 +22,41 @@ namespace ICSharpCode.Decompiler.Metadata @@ -22,12 +22,41 @@ namespace ICSharpCode.Decompiler.Metadata
{
public static class SignatureBlobComparer
{
internal static (int GenericParameterCount, int ParameterCount) ReadParameterCount(ref BlobReader reader)
{
if (reader.RemainingBytes == 0)
return (-1, -1);
var header = reader.ReadSignatureHeader();
int gp;
if (header.IsGeneric)
{
if (!reader.TryReadCompressedInteger(out gp))
gp = -1;
}
else
{
gp = 0;
}
if (!reader.TryReadCompressedInteger(out int p))
p = -1;
return (gp, p);
}
public static bool EqualsMethodSignature(BlobReader a, BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{
return EqualsMethodSignature(ref a, ref b, contextForA, contextForB);
return EqualsMethodSignature(ref a, ref b, contextForA, contextForB, false);
}
static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
public static bool EqualsMethodSignature(BlobReader a, BlobReader b, MetadataReader contextForA, MetadataReader contextForB, bool skipModifiers)
{
return EqualsMethodSignature(ref a, ref b, contextForA, contextForB, skipModifiers);
}
static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b,
MetadataReader contextForA, MetadataReader contextForB, bool skipModifiers)
{
SignatureHeader header;
// compare signature headers
@ -44,7 +73,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -44,7 +73,7 @@ namespace ICSharpCode.Decompiler.Metadata
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
int i = 0;
for (; i < totalParameterCount; i++)
@ -54,14 +83,14 @@ namespace ICSharpCode.Decompiler.Metadata @@ -54,14 +83,14 @@ namespace ICSharpCode.Decompiler.Metadata
// varargs sentinel
if (typeCode == 65)
break;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
}
for (; i < totalParameterCount; i++)
{
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
}
return true;
@ -76,7 +105,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -76,7 +105,7 @@ namespace ICSharpCode.Decompiler.Metadata
{
if (!IsSameCompressedInteger(ref a, ref b, out int typeCode))
return false;
return TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode);
return TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, false);
}
static bool IsSameCompressedInteger(ref BlobReader a, ref BlobReader b, out int value)
@ -89,7 +118,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -89,7 +118,7 @@ namespace ICSharpCode.Decompiler.Metadata
return a.TryReadCompressedSignedInteger(out value) && b.TryReadCompressedSignedInteger(out int otherValue) && value == otherValue;
}
static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB, int typeCode)
static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB, int typeCode, bool skipModifiers)
{
switch (typeCode)
{
@ -118,18 +147,18 @@ namespace ICSharpCode.Decompiler.Metadata @@ -118,18 +147,18 @@ namespace ICSharpCode.Decompiler.Metadata
case 0x1D: // ELEMENT_TYPE_SZARRAY
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
return true;
case 0x1B: // ELEMENT_TYPE_FNPTR
if (!EqualsMethodSignature(ref a, ref b, contextForA, contextForB))
if (!EqualsMethodSignature(ref a, ref b, contextForA, contextForB, skipModifiers))
return false;
return true;
case 0x14: // ELEMENT_TYPE_ARRAY
// element type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
// rank
if (!IsSameCompressedInteger(ref a, ref b, out _))
@ -154,19 +183,19 @@ namespace ICSharpCode.Decompiler.Metadata @@ -154,19 +183,19 @@ namespace ICSharpCode.Decompiler.Metadata
case 0x1F: // ELEMENT_TYPE_CMOD_REQD
case 0x20: // ELEMENT_TYPE_CMOD_OPT
// modifier
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB) && !skipModifiers)
return false;
// unmodified type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
return true;
case 0x15: // ELEMENT_TYPE_GENERICINST
// generic type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int numOfArguments))
return false;
@ -174,7 +203,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -174,7 +203,7 @@ namespace ICSharpCode.Decompiler.Metadata
{
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode, skipModifiers))
return false;
}
return true;
@ -200,6 +229,8 @@ namespace ICSharpCode.Decompiler.Metadata @@ -200,6 +229,8 @@ namespace ICSharpCode.Decompiler.Metadata
var typeB = b.ReadTypeHandle();
if (typeA.IsNil || typeB.IsNil)
return false;
if (contextForA == contextForB)
return typeA.Equals(typeB);
return typeA.GetFullTypeName(contextForA) == typeB.GetFullTypeName(contextForB);
}
}

Loading…
Cancel
Save