diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc
index f11fe9431c8dd7..a774eb8214bb2b 100644
--- a/src/coreclr/dlls/mscorrc/mscorrc.rc
+++ b/src/coreclr/dlls/mscorrc/mscorrc.rc
@@ -593,6 +593,7 @@ BEGIN
BFA_MISSING_DELEGATE_METHOD "Missing definition for required runtime implemented delegate method."
BFA_MULT_TYPE_SAME_NAME "Duplicate type with name '%1' in assembly '%2'."
BFA_INVALID_METHOD_TOKEN "Bad method token."
+ BFA_BAD_ASYNC_METHOD "Bad use of RuntimeAsync flag."
BFA_ECALLS_MUST_BE_IN_SYS_MOD "ECall methods must be packaged into a system module."
BFA_CANT_GET_CLASSLAYOUT "Could not get classlayout."
BFA_CALLCONV_NOT_LOCAL_SIG "Signature is not IMAGE_CEE_CS_CALLCONV_LOCAL_SIG."
diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h
index f3621378343c9a..822fd8b3b83397 100644
--- a/src/coreclr/dlls/mscorrc/resource.h
+++ b/src/coreclr/dlls/mscorrc/resource.h
@@ -366,6 +366,7 @@
#define BFA_MISSING_DELEGATE_METHOD 0x2030
#define BFA_MULT_TYPE_SAME_NAME 0x2031
#define BFA_INVALID_METHOD_TOKEN 0x2032
+#define BFA_BAD_ASYNC_METHOD 0x2033
#define BFA_ECALLS_MUST_BE_IN_SYS_MOD 0x2034
#define BFA_CANT_GET_CLASSLAYOUT 0x2035
#define BFA_CALLCONV_NOT_LOCAL_SIG 0x2036
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index f1d765dc8b3844..e74f48d4eebcd1 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -4279,6 +4279,11 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes)
ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramGenericMethod, this.MethodBeingCompiled);
}
+ if (this.MethodBeingCompiled.IsAsync)
+ {
+ ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramAsync, this.MethodBeingCompiled);
+ }
+
#if READYTORUN
// TODO: enable this check in full AOT
if (Marshaller.IsMarshallingRequired(this.MethodBeingCompiled.Signature, ((MetadataType)this.MethodBeingCompiled.OwningType).Module, this.MethodBeingCompiled.GetUnmanagedCallersOnlyMethodCallingConventions())) // Only blittable arguments
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs b/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs
index 97363c783f8a3e..b2ea129eea4c21 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs
@@ -39,6 +39,7 @@ public enum ExceptionStringID
InvalidProgramGenericMethod,
InvalidProgramNonBlittableTypes,
InvalidProgramMultipleCallConv,
+ InvalidProgramAsync,
// BadImageFormatException
BadImageFormatGeneric,
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx b/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx
index 3fc29a898ac3dd..53f193ad0321f2 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx
+++ b/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx
@@ -156,6 +156,9 @@
Failed to load assembly '{0}'
+
+ UnmanagedCallersOnly attribute specified on async method '{0}'
+
Invalid IL or CLR metadata
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs b/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs
index 36b9c43b67e172..f4760fb0d257c1 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs
@@ -23,6 +23,11 @@ private static MethodIL TryGetRuntimeImplementedMethodIL(MethodDesc method)
Debug.Assert(method.IsRuntimeImplemented);
+ if (method.IsAsync)
+ {
+ ThrowHelper.ThrowBadImageFormatException();
+ }
+
TypeDesc owningType = method.OwningType;
if (owningType.IsDelegate)
diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs
index 36cdc01805540b..87b1abf91cc1b6 100644
--- a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs
@@ -103,7 +103,7 @@ public static UnmanagedCallingConventions GetPInvokeMethodCallingConventions(thi
{
Debug.Assert(method.IsPInvoke);
- UnmanagedCallingConventions result;
+ UnmanagedCallingConventions result = 0;
if (method is Internal.IL.Stubs.PInvokeTargetNativeMethod pinvokeTarget)
method = pinvokeTarget.Target;
@@ -116,9 +116,9 @@ public static UnmanagedCallingConventions GetPInvokeMethodCallingConventions(thi
&& (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)UnmanagedCallingConventions.Thiscall);
result = (UnmanagedCallingConventions)unmanagedCallConv;
}
- else
+ else if (method is EcmaMethod ecmaMethod)
{
- CustomAttributeValue? unmanagedCallConvAttribute = ((EcmaMethod)method).GetDecodedCustomAttribute("System.Runtime.InteropServices", "UnmanagedCallConvAttribute");
+ CustomAttributeValue? unmanagedCallConvAttribute = ecmaMethod.GetDecodedCustomAttribute("System.Runtime.InteropServices", "UnmanagedCallConvAttribute");
if (unmanagedCallConvAttribute != null)
{
result = GetUnmanagedCallingConventionFromAttribute(unmanagedCallConvAttribute.Value, method.Context);
@@ -127,10 +127,10 @@ public static UnmanagedCallingConventions GetPInvokeMethodCallingConventions(thi
{
result = GetPlatformDefaultUnmanagedCallingConvention(method.Context);
}
- }
- if (method.HasCustomAttribute("System.Runtime.InteropServices", "SuppressGCTransitionAttribute"))
- result |= UnmanagedCallingConventions.IsSuppressGcTransition;
+ if (method.HasCustomAttribute("System.Runtime.InteropServices", "SuppressGCTransitionAttribute"))
+ result |= UnmanagedCallingConventions.IsSuppressGcTransition;
+ }
return result;
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs
index 945284e43abc53..3b6c61264f1302 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs
@@ -25,6 +25,10 @@ public PInvokeILProvider(PInvokeILEmitterConfiguration pInvokeILEmitterConfigura
public override MethodIL GetMethodIL(MethodDesc method)
{
+ if (method.IsAsync)
+ {
+ ThrowHelper.ThrowBadImageFormatException();
+ }
return PInvokeILEmitter.EmitIL(method, _pInvokeILEmitterConfiguration, _interopStateManager);
}
diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp
index 75dd154611d003..2e4179eed9c3a0 100644
--- a/src/coreclr/vm/comdelegate.cpp
+++ b/src/coreclr/vm/comdelegate.cpp
@@ -2045,6 +2045,10 @@ void COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(MethodDesc* pMD)
if (pMD->HasClassOrMethodInstantiation())
EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_GenericMethod")));
+ // No async methods
+ if (pMD->IsAsyncMethod())
+ EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_AsyncMethod")));
+
// Arguments - Scenarios involving UnmanagedCallersOnly are handled during the jit.
bool unmanagedCallersOnlyRequiresMarshalling = false;
if (PInvoke::MarshalingRequired(pMD, NULL, NULL, NULL, unmanagedCallersOnlyRequiresMarshalling))
diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp
index af8a66a0a992fc..be99ec36a97810 100644
--- a/src/coreclr/vm/dllimport.cpp
+++ b/src/coreclr/vm/dllimport.cpp
@@ -100,6 +100,7 @@ StubSigDesc::StubSigDesc(MethodDesc *pMD)
GC_NOTRIGGER;
SUPPORTS_DAC;
PRECONDITION(pMD != NULL);
+ PRECONDITION(!pMD->IsAsyncMethod());
}
CONTRACTL_END;
@@ -108,9 +109,6 @@ StubSigDesc::StubSigDesc(MethodDesc *pMD)
m_sig = pMD->GetSignature();
m_pModule = pMD->GetModule(); // Used for token resolution.
- // TODO: (async) revisit and examine if this needs to be supported somehow
- _ASSERTE(!pMD->IsAsyncMethod());
-
m_tkMethodDef = pMD->GetMemberDef();
SigTypeContext::InitTypeContext(pMD, &m_typeContext);
m_pMetadataModule = pMD->GetModule();
@@ -1131,7 +1129,6 @@ class ILStubState : public StubState
DWORD dwToken = 0;
if (pTargetMD)
{
- // TODO: (async) revisit and examine if this needs to be supported somehow
_ASSERTE(!pTargetMD->IsAsyncVariantMethod());
dwToken = pTargetMD->GetMemberDef();
}
@@ -2764,6 +2761,10 @@ void PInvokeStaticSigInfo::DllImportInit(
PRECONDITION(CheckPointer(pMD));
+ // P/Invoke methods should never be marked as async.
+ // This should be blocked in the class loader.
+ PRECONDITION(!pMD->IsAsyncMethod());
+
// These preconditions to prevent multithreaded regression
// where pMD->m_szLibName was passed in directly, cleared
// by this API, then accessed on another thread before being reset here.
@@ -2779,9 +2780,6 @@ void PInvokeStaticSigInfo::DllImportInit(
IMDInternalImport *pInternalImport = pMD->GetMDImport();
CorPinvokeMap mappingFlags = pmMaxValue;
mdModuleRef modref = mdModuleRefNil;
- // TODO: (async) revisit and examine if this needs to be supported somehow
- if (pMD->IsAsyncMethod())
- ThrowHR(COR_E_NOTSUPPORTED);
if (FAILED(pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, ppEntryPointName, &modref)))
{
@@ -3053,6 +3051,7 @@ namespace
STANDARD_VM_CHECK;
PRECONDITION(pMD != NULL);
PRECONDITION(pMD->IsPInvoke());
+ PRECONDITION(!pMD->IsAsyncMethod());
PRECONDITION(callConv != NULL);
}
CONTRACTL_END;
@@ -3060,9 +3059,7 @@ namespace
CorInfoCallConvExtension callConvLocal;
IMDInternalImport* pInternalImport = pMD->GetMDImport();
CorPinvokeMap mappingFlags = pmMaxValue;
- // TODO: (async) revisit and examine if this needs to be supported somehow
- if (pMD->IsAsyncMethod())
- ThrowHR(COR_E_NOTSUPPORTED);
+
HRESULT hr = pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, NULL /*pszImportName*/, NULL /*pmrImportDLL*/);
if (FAILED(hr))
@@ -3249,6 +3246,12 @@ BOOL PInvoke::MarshalingRequired(
{
STANDARD_VM_CHECK;
PRECONDITION(pMD != NULL || (!sigPointer.IsNull() && pModule != NULL));
+
+ // We should never see an async method here.
+ // Delegate Invoke methods should never be async.
+ // Async P/Invokes are not supported.
+ // Async UnmanagedCallersOnly methods are not supported.
+ PRECONDITION(pMD == NULL || !pMD->IsAsyncMethod());
}
CONTRACTL_END;
@@ -3324,10 +3327,6 @@ BOOL PInvoke::MarshalingRequired(
mdMethodDef methodToken = mdMethodDefNil;
if (pMD != NULL)
{
- // TODO: (async) revisit and examine if this needs to be supported somehow
- if (pMD->IsAsyncMethod())
- ThrowHR(COR_E_NOTSUPPORTED);
-
methodToken = pMD->GetMemberDef();
}
CollateParamTokens(pMDImport, methodToken, numArgs - 1, pParamTokenArray);
@@ -6080,12 +6079,10 @@ static void GetILStubForCalli(VASigCookie* pVASigCookie, MethodDesc* pMD)
if (pMD != NULL)
{
+ _ASSERTE(pMD->IsPInvoke());
+ _ASSERTE(!pMD->IsAsyncMethod());
PInvokeStaticSigInfo sigInfo(pMD);
- // TODO: (async) revisit and examine if this needs to be supported somehow
- if (pMD->IsAsyncMethod())
- ThrowHR(COR_E_NOTSUPPORTED);
-
md = pMD->GetMemberDef();
nlFlags = sigInfo.GetLinkFlags();
nlType = sigInfo.GetCharSet();
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index a55ed3964c0f32..0bcc93a46f1f91 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -3183,6 +3183,11 @@ MethodTableBuilder::EnumerateClassMethods()
CONSISTENCY_CHECK(hr == S_OK);
type = mcPInvoke;
}
+
+ if (IsMiAsync(dwImplFlags))
+ {
+ BuildMethodTableThrowException(BFA_BAD_ASYNC_METHOD);
+ }
}
else if (IsMiRuntime(dwImplFlags))
{
@@ -3227,6 +3232,11 @@ MethodTableBuilder::EnumerateClassMethods()
}
delegateMethodsSeen |= newDelegateMethodSeen;
+
+ if (IsMiAsync(dwImplFlags))
+ {
+ BuildMethodTableThrowException(BFA_BAD_ASYNC_METHOD);
+ }
}
else if (hasGenericMethodArgs)
{
@@ -3254,6 +3264,12 @@ MethodTableBuilder::EnumerateClassMethods()
// pointer-sized field pointing to COM interop data which are
// allocated lazily when/if the MD actually gets used for interop.
type = mcComInterop;
+
+ // The interface method itself should never be marked as a runtime-async method.
+ if (IsMiAsync(dwImplFlags))
+ {
+ BuildMethodTableThrowException(BFA_BAD_ASYNC_METHOD);
+ }
}
else
#endif // !FEATURE_COMINTEROP
@@ -3432,15 +3448,13 @@ MethodTableBuilder::EnumerateClassMethods()
}
MethodClassification asyncVariantType = type;
-#ifdef FEATURE_COMINTEROP
- if (type == mcComInterop)
+ if (type != mcIL && type != mcInstantiated)
{
- // For COM interop methods,
- // we don't want to treat the async variant as a COM Interop method
- // (as it isn't, it's a transient IL method).
+ // Don't treat the async variant of special method kinds as
+ // the special method kind.
+ // The async variant methods are always IL methods with a transient implementation.
asyncVariantType = mcIL;
}
-#endif // FEATURE_COMINTEROP
Signature newMemberSig(pNewMemberSignature, cAsyncThunkMemberSignature);
pNewMethod = new (GetStackingAllocator()) bmtMDMethod(
diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
index bf34d7bec20f87..f5e642b7ee6ca8 100644
--- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
@@ -3107,6 +3107,9 @@
Not supported in a non-reflected type.
+
+ Async methods with UnmanagedCallersOnlyAttribute are invalid.
+
Non-static methods with UnmanagedCallersOnlyAttribute are invalid.
diff --git a/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.cs b/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.cs
index 529a4dec715ca3..74d239c2f16dd3 100644
--- a/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.cs
+++ b/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.cs
@@ -58,17 +58,36 @@ static async Task TestAsyncMethod(ITaskComServer_AsDispatchOnly obj)
}
}
}
+
+ [Fact]
+ public static void TaskReturningPInvokeWithComMarshalling()
+ {
+ Task originalTask = new(() => {});
+ Task result = RunTask(originalTask);
+
+ originalTask.Start();
+
+ result.GetAwaiter().GetResult();
+
+ static async Task RunTask(Task task)
+ {
+ await RuntimeAsyncNative.PassThroughTask(task);
+ }
+ }
}
public static class RuntimeAsyncNative
{
- [DllImport("RuntimeAsyncNative")]
+ [DllImport(nameof(RuntimeAsyncNative))]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool ValidateSlotLayoutForDefaultInterface([MarshalAs(UnmanagedType.Interface)] object comObject, int expectedIntValue, float expectedFloatValue);
- [DllImport("RuntimeAsyncNative")]
+ [DllImport(nameof(RuntimeAsyncNative))]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool ValidateSlotLayoutForInterface([MarshalAs(UnmanagedType.Interface)] object comObject, float expectedFloatValue);
+
+ [DllImport(nameof(RuntimeAsyncNative))]
+ public static extern Task PassThroughTask(Task task);
}
[ComVisible(true)]
diff --git a/src/tests/Interop/COM/RuntimeAsync/RuntimeAsyncNative.cpp b/src/tests/Interop/COM/RuntimeAsync/RuntimeAsyncNative.cpp
index d4e2b4a41cc942..da04e40a05ca5a 100644
--- a/src/tests/Interop/COM/RuntimeAsync/RuntimeAsyncNative.cpp
+++ b/src/tests/Interop/COM/RuntimeAsync/RuntimeAsyncNative.cpp
@@ -79,3 +79,9 @@ extern "C" DLL_EXPORT bool STDMETHODCALLTYPE ValidateSlotLayoutForInterface(IUnk
return true;
}
+
+extern "C" DLL_EXPORT IUnknown* STDMETHODCALLTYPE PassThroughTask(IUnknown* pUnk)
+{
+ pUnk->AddRef();
+ return pUnk;
+}
diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il
index 7090382368e3b7..50edd29ba448bf 100644
--- a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il
+++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il
@@ -305,3 +305,41 @@
IL_0001: ret
}
}
+
+.class public auto ansi beforefieldinit InvalidCSharp.RuntimeAsyncUnmanagedCallersOnly
+ extends [System.Runtime]System.Object
+{
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor () cil managed
+ {
+ .maxstack 8
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+
+ .method public hidebysig static
+ class [System.Runtime]System.Threading.Tasks.Task AsyncMethodReturningTask (
+ ) cil managed async
+ {
+ .custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = (
+ 01 00 00 00
+ )
+ .maxstack 8
+
+ IL_0001: ret
+ }
+
+ .method public hidebysig static
+ int32 AsyncMethodWithBlittableReturnType (
+ ) cil managed async
+ {
+ .custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = (
+ 01 00 00 00
+ )
+ .maxstack 8
+
+ IL_0000: ldc.i4.0
+ IL_0001: ret
+ }
+}
diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs
index 7d4d3c57d4d85a..702970b956b4a2 100644
--- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs
+++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs
@@ -8,9 +8,11 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
+using System.Threading.Tasks;
using Xunit;
using InvalidCSharp;
+[ActiveIssue("https://github.com/dotnet/runtime/issues/91388", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.PlatformDoesNotSupportNativeTestAssets))]
public unsafe class Program
{
public static class UnmanagedCallersOnlyDll
@@ -26,37 +28,6 @@ public static class UnmanagedCallersOnlyDll
private delegate int IntNativeMethodInvoker();
private delegate void NativeMethodInvoker();
- [Fact]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/91388", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.PlatformDoesNotSupportNativeTestAssets))]
- public static int TestEntryPoint()
- {
- try
- {
- NegativeTest_NonStaticMethod();
- NegativeTest_ViaDelegate();
- NegativeTest_NonBlittable();
- NegativeTest_InstantiatedGenericArguments();
- NegativeTest_FromInstantiatedGenericClass();
- TestUnmanagedCallersOnlyViaUnmanagedCalli();
- TestPInvokeMarkedWithUnmanagedCallersOnly();
- TestUnmanagedCallersOnlyWithGeneric();
-
- // Exception handling interop is only supported on CoreCLR Windows.
- if (TestLibrary.Utilities.IsWindows && !TestLibrary.Utilities.IsMonoRuntime && !TestLibrary.Utilities.IsCoreClrInterpreter)
- {
- TestUnmanagedCallersOnlyValid_ThrowException();
- TestUnmanagedCallersOnlyViaUnmanagedCalli_ThrowException();
- }
- }
- catch (Exception e)
- {
- Console.WriteLine($"Test Failure: {e}");
- return 101;
- }
-
- return 100;
- }
-
private static int DoubleImpl(int n)
{
return 2 * n;
@@ -70,6 +41,7 @@ public static int CallbackThrows(int val)
throw new Exception() { HResult = CallbackThrowsErrorCode };
}
+ [ConditionalFact(typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsExceptionInteropSupported))]
public static void TestUnmanagedCallersOnlyValid_ThrowException()
{
Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyValid_ThrowException)}...");
@@ -79,6 +51,7 @@ public static void TestUnmanagedCallersOnlyValid_ThrowException()
Assert.Equal(-1, UnmanagedCallersOnlyDll.CallManagedProcCatchException((IntPtr)(delegate* unmanaged)&CallbackThrows, n));
}
+ [Fact]
public static void NegativeTest_ViaDelegate()
{
Console.WriteLine($"Running {nameof(NegativeTest_ViaDelegate)}...");
@@ -94,6 +67,7 @@ void CallAsDelegate()
}
}
+ [Fact]
public static void NegativeTest_NonStaticMethod()
{
Console.WriteLine($"Running {nameof(NegativeTest_NonStaticMethod)}...");
@@ -109,6 +83,7 @@ public static int CallbackMethodNonBlittable(bool x1)
return -1;
}
+ [Fact]
public static void NegativeTest_NonBlittable()
{
Console.WriteLine($"Running {nameof(NegativeTest_NonBlittable)}...");
@@ -121,6 +96,7 @@ public static void NegativeTest_NonBlittable()
Assert.Throws(() => { UnmanagedCallersOnlyDll.CallManagedProc(UnmanagedCallersOnlyWithByRefs.GetWithByRefOutFunctionPointer(), n); });
}
+ [Fact]
public static void NegativeTest_InstantiatedGenericArguments()
{
Console.WriteLine($"Running {nameof(NegativeTest_InstantiatedGenericArguments)}...");
@@ -130,6 +106,7 @@ public static void NegativeTest_InstantiatedGenericArguments()
Assert.Throws(() => { UnmanagedCallersOnlyDll.CallManagedProc((IntPtr)(delegate* unmanaged)&Callbacks.CallbackMethodGeneric, n); });
}
+ [Fact]
public static void NegativeTest_FromInstantiatedGenericClass()
{
Console.WriteLine($"Running {nameof(NegativeTest_FromInstantiatedGenericClass)}...");
@@ -145,6 +122,7 @@ public static int CallbackViaUnmanagedCalli(int val)
return DoubleImpl(val);
}
+ [Fact]
public static void TestUnmanagedCallersOnlyViaUnmanagedCalli()
{
Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyViaUnmanagedCalli)}...");
@@ -161,6 +139,7 @@ public static int CallbackViaUnmanagedCalliThrows(int val)
throw new Exception() { HResult = CallbackThrowsErrorCode };
}
+ [ConditionalFact(typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsExceptionInteropSupported))]
public static void TestUnmanagedCallersOnlyViaUnmanagedCalli_ThrowException()
{
Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyViaUnmanagedCalli_ThrowException)}...");
@@ -179,6 +158,7 @@ public static void TestUnmanagedCallersOnlyViaUnmanagedCalli_ThrowException()
}
}
+ [Fact]
public static void TestPInvokeMarkedWithUnmanagedCallersOnly()
{
Console.WriteLine($"Running {nameof(TestPInvokeMarkedWithUnmanagedCallersOnly)}...");
@@ -195,6 +175,7 @@ public static void TestPInvokeMarkedWithUnmanagedCallersOnly()
Assert.Throws(() => ((delegate* unmanaged)&CallingUnmanagedCallersOnlyDirectly.PInvokeMarkedWithUnmanagedCallersOnly)(n));
}
+ [Fact]
public static void TestUnmanagedCallersOnlyWithGeneric()
{
Assert.Equal(0, ((delegate* unmanaged, int>)&BlittableGenericStruct)(new Blittable()));
@@ -209,6 +190,20 @@ public static void TestUnmanagedCallersOnlyWithGeneric()
=> ((delegate* unmanaged)(void*)(delegate* unmanaged, int>)&InvalidGenericUnmanagedCallersOnlyParameters.GenericStructWithObjectField)((nint)1));
}
+ [Fact]
+ [SkipOnMono("Mono doesn't support runtime async and doesn't check the async bit.")]
+ public static void TestUnmanagedCallersOnlyWithRuntimeAsync()
+ {
+ AssertExtensions.ThrowsAny(() =>
+ {
+ ((delegate* unmanaged)&RuntimeAsyncUnmanagedCallersOnly.AsyncMethodReturningTask)();
+ });
+ AssertExtensions.ThrowsAny(() =>
+ {
+ ((delegate* unmanaged)&RuntimeAsyncUnmanagedCallersOnly.AsyncMethodWithBlittableReturnType)();
+ });
+ }
+
internal struct Blittable where T : unmanaged
{
T Value;