Skip to content

Virt call unsafe accessor tests #89220

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

Merged
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
11 changes: 5 additions & 6 deletions src/coreclr/vm/prestub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1266,13 +1266,12 @@ namespace

MethodDesc* targetMaybe = NULL;

// Following the iteration pattern found in MemberLoader::FindMethod().
// Reverse order is recommended - see comments in MemberLoader::FindMethod().
MethodTable::MethodIterator iter(targetType.AsMethodTable());
iter.MoveToEnd();
for (; iter.IsValid(); iter.Prev())
// Following a similar iteration pattern found in MemberLoader::FindMethod().
// However, we are only operating on the current type not walking the type hierarchy.
MethodTable::IntroducedMethodIterator iter(targetType.AsMethodTable());
for (; iter.IsValid(); iter.Next())
{
MethodDesc* curr = iter.GetDeclMethodDesc();
MethodDesc* curr = iter.GetMethodDesc();

// Check the target and current method match static/instance state.
if (cxt.IsTargetStatic != (!!curr->IsStatic()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public enum UnsafeAccessorKind
/// The runtime will try to find the matching method or field and forward the call
/// to it. If the matching method or field is not found, the body of the <code>extern</code>
/// method will throw <see cref="MissingFieldException" /> or <see cref="MissingMethodException" />.
/// Only the specific type defined will be examined for inaccessible members. The type hierarchy
/// is not walked looking for a match.
///
/// For <see cref="UnsafeAccessorKind.Method"/>, <see cref="UnsafeAccessorKind.StaticMethod"/>,
/// <see cref="UnsafeAccessorKind.Field"/>, and <see cref="UnsafeAccessorKind.StaticField"/>, the type of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,32 +373,56 @@ public static void Verify_ManagedUnmanagedFunctionPointersDontMatch()
extern static string CallManagedMethod(UserDataClass d, delegate* unmanaged[Cdecl]<void> fptr);
}

class InheritanceBase
abstract class InheritanceBase
{
private static string OnBase() => nameof(OnBase);
private static string FieldOnBase = nameof(FieldOnBase);
protected abstract string Abstract();
protected virtual string Virtual() => $"{nameof(InheritanceBase)}.{nameof(Virtual)}";
protected virtual string NewVirtual() => $"{nameof(InheritanceBase)}.{nameof(NewVirtual)}";
protected virtual string BaseVirtual() => $"{nameof(InheritanceBase)}.{nameof(BaseVirtual)}";
}

class InheritanceDerived : InheritanceBase
{
private static string OnDerived() => nameof(OnDerived);
private static string FieldOnDerived = nameof(FieldOnDerived);
protected override string Abstract() => $"{nameof(InheritanceDerived)}.{nameof(Abstract)}";
protected override string Virtual() => $"{nameof(InheritanceDerived)}.{nameof(Virtual)}";
protected new virtual string NewVirtual() => $"{nameof(InheritanceDerived)}.{nameof(NewVirtual)}";
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/89212", TestRuntimes.Mono)]
public static void Verify_InheritanceMethodResolution()
{
Console.WriteLine($"Running {nameof(Verify_InheritanceMethodResolution)}");

var instance = new InheritanceDerived();
Assert.Throws<MissingMethodException>(() => OnBase(instance));
Assert.Throws<MissingMethodException>(() => BaseVirtual(instance));
Assert.Equal(nameof(OnDerived), OnDerived(instance));
Assert.Equal($"{nameof(InheritanceDerived)}.{nameof(Abstract)}", Abstract(instance));
Assert.Equal($"{nameof(InheritanceDerived)}.{nameof(Virtual)}", Virtual(instance));
Assert.Equal($"{nameof(InheritanceBase)}.{nameof(NewVirtual)}", NewVirtual(instance));

[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = nameof(OnBase))]
extern static string OnBase(InheritanceDerived i);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(BaseVirtual))]
extern static string BaseVirtual(InheritanceDerived target);

[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = nameof(OnDerived))]
extern static string OnDerived(InheritanceDerived i);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Abstract))]
extern static string Abstract(InheritanceBase target);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Virtual))]
extern static string Virtual(InheritanceBase target);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(NewVirtual))]
extern static string NewVirtual(InheritanceBase target);
}

[Fact]
Expand Down Expand Up @@ -436,7 +460,7 @@ public static void Verify_InvalidTargetUnsafeAccessor()
() => FieldNotFound(null));
AssertExtensions.ThrowsMissingMemberException<MissingFieldException>(
isNativeAot ? null : UserDataClass.StaticFieldName,
() =>
() =>
{
UserDataValue value = default;
FieldNotFoundStaticMismatch1(ref value);
Expand Down Expand Up @@ -489,6 +513,8 @@ public static void Verify_InvalidTargetUnsafeAccessor()
[ActiveIssue("https://github.com/dotnet/runtime/issues/86040", TestRuntimes.Mono)]
public static void Verify_InvalidTargetUnsafeAccessorAmbiguousMatch()
{
Console.WriteLine($"Running {nameof(Verify_InvalidTargetUnsafeAccessorAmbiguousMatch)}");

Assert.Throws<AmbiguousMatchException>(
() => CallAmbiguousMethod(CallPrivateConstructorClass(), null));

Expand Down