Skip to content

Commit f695b49

Browse files
Virt call unsafe accessor tests (#89220)
* UnsafeAccessors are limited to lookup on the defined typed. * Update documentation for attribute. --------- Co-authored-by: vitek-karas <10670590+vitek-karas@users.noreply.github.com>
1 parent a4a8e8e commit f695b49

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

src/coreclr/vm/prestub.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,13 +1266,12 @@ namespace
12661266

12671267
MethodDesc* targetMaybe = NULL;
12681268

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

12771276
// Check the target and current method match static/instance state.
12781277
if (cxt.IsTargetStatic != (!!curr->IsStatic()))

src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/UnsafeAccessorAttribute.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ public enum UnsafeAccessorKind
4545
/// The runtime will try to find the matching method or field and forward the call
4646
/// to it. If the matching method or field is not found, the body of the <code>extern</code>
4747
/// method will throw <see cref="MissingFieldException" /> or <see cref="MissingMethodException" />.
48+
/// Only the specific type defined will be examined for inaccessible members. The type hierarchy
49+
/// is not walked looking for a match.
4850
///
4951
/// For <see cref="UnsafeAccessorKind.Method"/>, <see cref="UnsafeAccessorKind.StaticMethod"/>,
5052
/// <see cref="UnsafeAccessorKind.Field"/>, and <see cref="UnsafeAccessorKind.StaticField"/>, the type of

src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,32 +373,56 @@ public static void Verify_ManagedUnmanagedFunctionPointersDontMatch()
373373
extern static string CallManagedMethod(UserDataClass d, delegate* unmanaged[Cdecl]<void> fptr);
374374
}
375375

376-
class InheritanceBase
376+
abstract class InheritanceBase
377377
{
378378
private static string OnBase() => nameof(OnBase);
379379
private static string FieldOnBase = nameof(FieldOnBase);
380+
protected abstract string Abstract();
381+
protected virtual string Virtual() => $"{nameof(InheritanceBase)}.{nameof(Virtual)}";
382+
protected virtual string NewVirtual() => $"{nameof(InheritanceBase)}.{nameof(NewVirtual)}";
383+
protected virtual string BaseVirtual() => $"{nameof(InheritanceBase)}.{nameof(BaseVirtual)}";
380384
}
381385

382386
class InheritanceDerived : InheritanceBase
383387
{
384388
private static string OnDerived() => nameof(OnDerived);
385389
private static string FieldOnDerived = nameof(FieldOnDerived);
390+
protected override string Abstract() => $"{nameof(InheritanceDerived)}.{nameof(Abstract)}";
391+
protected override string Virtual() => $"{nameof(InheritanceDerived)}.{nameof(Virtual)}";
392+
protected new virtual string NewVirtual() => $"{nameof(InheritanceDerived)}.{nameof(NewVirtual)}";
386393
}
387394

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

393401
var instance = new InheritanceDerived();
394402
Assert.Throws<MissingMethodException>(() => OnBase(instance));
403+
Assert.Throws<MissingMethodException>(() => BaseVirtual(instance));
395404
Assert.Equal(nameof(OnDerived), OnDerived(instance));
405+
Assert.Equal($"{nameof(InheritanceDerived)}.{nameof(Abstract)}", Abstract(instance));
406+
Assert.Equal($"{nameof(InheritanceDerived)}.{nameof(Virtual)}", Virtual(instance));
407+
Assert.Equal($"{nameof(InheritanceBase)}.{nameof(NewVirtual)}", NewVirtual(instance));
396408

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

412+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(BaseVirtual))]
413+
extern static string BaseVirtual(InheritanceDerived target);
414+
400415
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = nameof(OnDerived))]
401416
extern static string OnDerived(InheritanceDerived i);
417+
418+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Abstract))]
419+
extern static string Abstract(InheritanceBase target);
420+
421+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Virtual))]
422+
extern static string Virtual(InheritanceBase target);
423+
424+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(NewVirtual))]
425+
extern static string NewVirtual(InheritanceBase target);
402426
}
403427

404428
[Fact]
@@ -436,7 +460,7 @@ public static void Verify_InvalidTargetUnsafeAccessor()
436460
() => FieldNotFound(null));
437461
AssertExtensions.ThrowsMissingMemberException<MissingFieldException>(
438462
isNativeAot ? null : UserDataClass.StaticFieldName,
439-
() =>
463+
() =>
440464
{
441465
UserDataValue value = default;
442466
FieldNotFoundStaticMismatch1(ref value);
@@ -489,6 +513,8 @@ public static void Verify_InvalidTargetUnsafeAccessor()
489513
[ActiveIssue("https://github.com/dotnet/runtime/issues/86040", TestRuntimes.Mono)]
490514
public static void Verify_InvalidTargetUnsafeAccessorAmbiguousMatch()
491515
{
516+
Console.WriteLine($"Running {nameof(Verify_InvalidTargetUnsafeAccessorAmbiguousMatch)}");
517+
492518
Assert.Throws<AmbiguousMatchException>(
493519
() => CallAmbiguousMethod(CallPrivateConstructorClass(), null));
494520

0 commit comments

Comments
 (0)