Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ private static bool DoesMethodMatchUnsafeAccessorDeclaration(ref GenerationConte
return false;
}

// Validate generic parameter.
if (declSig.GenericParameterCount != maybeSig.GenericParameterCount)
{
return false;
}

// Validate argument count and return type
if (context.Kind == UnsafeAccessorKind.Constructor)
{
Expand Down
22 changes: 17 additions & 5 deletions src/coreclr/vm/prestub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1190,14 +1190,26 @@ namespace
return false;
}

// Handle generic param count
DWORD declGenericCount = 0;
DWORD methodGenericCount = 0;
// Handle generic signature
if (callConvDecl & IMAGE_CEE_CS_CALLCONV_GENERIC)
{
if (!(callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC))
return false;

DWORD declGenericCount = 0;
DWORD methodGenericCount = 0;
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declGenericCount));
if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC)
IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &methodGenericCount));

if (declGenericCount != methodGenericCount)
return false;
}
else if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC)
{
// Method is generic but declaration is not
return false;
}

DWORD declArgCount;
DWORD methodArgCount;
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declArgCount));
Expand Down Expand Up @@ -3541,7 +3553,7 @@ static PCODE getHelperForStaticBase(Module * pModule, CORCOMPILE_FIXUP_BLOB_KIND
bool threadStatic = (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER);

CorInfoHelpFunc helper;

if (threadStatic)
{
if (GCStatic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,76 @@ public static void Verify_Generic_AccessFieldClass()
}
}

class AmbiguousMethodName
{
private void M() { }
private void M<T>() { }
private void N() { }

private static void SM() { }
private static void SM<U>() { }
private static void SN() { }
}

static class AccessorsAmbiguousMethodName
{
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
public extern static void CallM(AmbiguousMethodName a);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
public extern static void CallM<T>(AmbiguousMethodName a);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "N")]
public extern static void CallN_MissingMethod<T>(AmbiguousMethodName a);

[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")]
public extern static void CallSM(AmbiguousMethodName a);

[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")]
public extern static void CallSM<U>(AmbiguousMethodName a);

[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SN")]
public extern static void CallSN_MissingMethod<T>(AmbiguousMethodName a);
}

[Fact]
public static void Verify_Generic_AmbiguousMethodName()
{
Console.WriteLine($"Running {nameof(Verify_Generic_AmbiguousMethodName)}");

{
AmbiguousMethodName a = new();
AccessorsAmbiguousMethodName.CallM(a);
AccessorsAmbiguousMethodName.CallM<int>(a);
AccessorsAmbiguousMethodName.CallM<string>(a);
AccessorsAmbiguousMethodName.CallM<Guid>(a);
Assert.Throws<MissingMethodException>(() => AccessorsAmbiguousMethodName.CallN_MissingMethod<int>(a));
}

{
AccessorsAmbiguousMethodName.CallSM(null);
AccessorsAmbiguousMethodName.CallSM<int>(null);
AccessorsAmbiguousMethodName.CallSM<string>(null);
AccessorsAmbiguousMethodName.CallSM<Guid>(null);
Assert.Throws<MissingMethodException>(() => AccessorsAmbiguousMethodName.CallSN_MissingMethod<int>(null));
}
}

class Base
{
protected virtual string CreateMessageGeneric<T>(T t) => $"{nameof(Base)}:{t}";
protected virtual string CreateMessage<T>(T t) => $"{nameof(Base)}<>:{t}";
}

class GenericBase<T> : Base
class GenericBase<U> : Base
{
protected virtual string CreateMessage(T t) => $"{nameof(GenericBase<T>)}:{t}";
protected override string CreateMessageGeneric<U>(U u) => $"{nameof(GenericBase<T>)}:{u}";
protected virtual string CreateMessage(U u) => $"{nameof(GenericBase<U>)}:{u}";
protected override string CreateMessage<V>(V v) => $"{nameof(GenericBase<U>)}<>:{v}";
}

sealed class Derived1 : GenericBase<string>
{
protected override string CreateMessage(string u) => $"{nameof(Derived1)}:{u}";
protected override string CreateMessageGeneric<U>(U t) => $"{nameof(Derived1)}:{t}";
protected override string CreateMessage<W>(W w) => $"{nameof(Derived1)}<>:{w}";
}

sealed class Derived2 : GenericBase<string>
Expand All @@ -209,33 +264,33 @@ public static void Verify_Generic_InheritanceMethodResolution()
Console.WriteLine($"Running {nameof(Verify_Generic_InheritanceMethodResolution)}");
{
Base a = new();
Assert.Equal($"{nameof(Base)}:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(Base)}:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(Base)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
Assert.Equal($"{nameof(Base)}<>:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(Base)}<>:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(Base)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
}
{
GenericBase<int> a = new();
Assert.Equal($"{nameof(GenericBase<int>)}:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(GenericBase<int>)}:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(GenericBase<int>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
Assert.Equal($"{nameof(GenericBase<int>)}<>:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(GenericBase<int>)}<>:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(GenericBase<int>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
}
{
GenericBase<string> a = new();
Assert.Equal($"{nameof(GenericBase<string>)}:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(GenericBase<string>)}:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(GenericBase<string>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
Assert.Equal($"{nameof(GenericBase<string>)}<>:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(GenericBase<string>)}<>:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(GenericBase<string>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
}
{
GenericBase<Struct> a = new();
Assert.Equal($"{nameof(GenericBase<Struct>)}:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(GenericBase<Struct>)}:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(GenericBase<Struct>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
}
{
Derived1 a = new();
Assert.Equal($"{nameof(Derived1)}:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(Derived1)}:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(Derived1)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
Assert.Equal($"{nameof(Derived1)}<>:1", CreateMessage<int>(a, 1));
Assert.Equal($"{nameof(Derived1)}<>:{expect}", CreateMessage<string>(a, expect));
Assert.Equal($"{nameof(Derived1)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
}
{
// Verify resolution of generic override logic.
Expand All @@ -245,7 +300,7 @@ public static void Verify_Generic_InheritanceMethodResolution()
Assert.Equal($"{nameof(GenericBase<string>)}:{expect}", Accessors<string>.CreateMessage(a2, expect));
}

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessageGeneric")]
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessage")]
extern static string CreateMessage<W>(Base b, W w);
}

Expand Down
Loading