Skip to content

Commit 23c468a

Browse files
committed
Fix check for invocation of async infrastructure methods via reflection
1 parent a2b94d3 commit 23c468a

File tree

3 files changed

+14
-7
lines changed

3 files changed

+14
-7
lines changed

src/coreclr/vm/reflectioninvocation.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -342,11 +342,6 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod(
342342
COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
343343
}
344344

345-
if (pMeth->IsAsyncMethod())
346-
{
347-
COMPlusThrow(kNotSupportedException, W("NotSupported_Async"));
348-
}
349-
350345
#ifdef _DEBUG
351346
if (g_pConfig->ShouldInvokeHalt(pMeth))
352347
{

src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ internal InvocationFlags ComputeAndUpdateInvocationFlags()
3232
{
3333
invocationFlags = InvocationFlags.NoInvoke;
3434
}
35+
// This check assumes that all MethodImplAttributes.Async methods on AsyncHelpers are the only non-task returning async methods
36+
// with special calling convention
37+
else if (declaringType == typeof(AsyncHelpers) && (GetMethodImplementationFlags() & MethodImplAttributes.Async) != 0)
38+
{
39+
invocationFlags = InvocationFlags.NoInvoke;
40+
}
3541
else if (declaringType.IsByRefLike) // Check for byref-like types
3642
{
3743
invocationFlags |= InvocationFlags.ContainsStackPointers;
@@ -60,6 +66,8 @@ static bool IsDisallowedByRefType(Type type)
6066
[DoesNotReturn]
6167
internal void ThrowNoInvokeException()
6268
{
69+
Type? declaringType = DeclaringType;
70+
6371
// method is on a class that contains stack pointers
6472
if ((InvocationFlags & InvocationFlags.ContainsStackPointers) != 0)
6573
{
@@ -71,7 +79,7 @@ internal void ThrowNoInvokeException()
7179
throw new NotSupportedException();
7280
}
7381
// method is generic or on a generic class
74-
else if (DeclaringType!.ContainsGenericParameters || ContainsGenericParameters)
82+
else if ((declaringType != null && declaringType.ContainsGenericParameters) || ContainsGenericParameters)
7583
{
7684
throw new InvalidOperationException(SR.Arg_UnboundGenParam);
7785
}
@@ -88,6 +96,10 @@ internal void ThrowNoInvokeException()
8896
if (elementType == typeof(void))
8997
throw new NotSupportedException(SR.NotSupported_ByRefToVoidReturn);
9098
}
99+
else if (declaringType == typeof(AsyncHelpers) && (GetMethodImplementationFlags() & MethodImplAttributes.Async) != 0)
100+
{
101+
throw new NotSupportedException(SR.NotSupported_Async);
102+
}
91103

92104
throw new TargetException();
93105
}

src/tests/async/reflection/reflection-simple.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public static void MethodInfo_Invoke_AsyncHelper()
2727
{
2828
var mi = typeof(System.Runtime.CompilerServices.AsyncHelpers).GetMethod("Await", BindingFlags.Static | BindingFlags.Public, new Type[] { typeof(Task) })!;
2929
Assert.NotNull(mi);
30-
Assert.Throws<TargetInvocationException>(() => mi.Invoke(null, new object[] { FooTask() }));
30+
Assert.Throws<NotSupportedException>(() => mi.Invoke(null, new object[] { FooTask() }));
3131

3232
// Sadly the following does not throw and results in UB
3333
// We cannot completely prevent putting a token of an Async method into IL stream.

0 commit comments

Comments
 (0)