Skip to content
Merged
1 change: 1 addition & 0 deletions src/coreclr/dlls/mscorrc/mscorrc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/dlls/mscorrc/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
jkotas marked this conversation as resolved.
Outdated
#define BFA_ECALLS_MUST_BE_IN_SYS_MOD 0x2034
#define BFA_CANT_GET_CLASSLAYOUT 0x2035
#define BFA_CALLCONV_NOT_LOCAL_SIG 0x2036
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/comdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2045,6 +2045,10 @@ void COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(MethodDesc* pMD)
if (pMD->HasClassOrMethodInstantiation())
EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_GenericMethod")));

// No async methods
Comment thread
jkoritzinsky marked this conversation as resolved.
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))
Expand Down
33 changes: 15 additions & 18 deletions src/coreclr/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ StubSigDesc::StubSigDesc(MethodDesc *pMD)
GC_NOTRIGGER;
SUPPORTS_DAC;
PRECONDITION(pMD != NULL);
PRECONDITION(!pMD->IsAsyncMethod());
Comment thread
jkoritzinsky marked this conversation as resolved.
}
CONTRACTL_END;

Expand All @@ -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();
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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.
Expand All @@ -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)))
{
Expand Down Expand Up @@ -3053,16 +3051,15 @@ namespace
STANDARD_VM_CHECK;
PRECONDITION(pMD != NULL);
PRECONDITION(pMD->IsPInvoke());
PRECONDITION(!pMD->IsAsyncMethod());
PRECONDITION(callConv != NULL);
}
CONTRACTL_END;

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);

Comment thread
jkoritzinsky marked this conversation as resolved.

HRESULT hr = pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, NULL /*pszImportName*/, NULL /*pmrImportDLL*/);
if (FAILED(hr))
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down
26 changes: 20 additions & 6 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down Expand Up @@ -3227,6 +3232,11 @@ MethodTableBuilder::EnumerateClassMethods()
}

delegateMethodsSeen |= newDelegateMethodSeen;

if (IsMiAsync(dwImplFlags))
{
BuildMethodTableThrowException(BFA_BAD_ASYNC_METHOD);
}
}
else if (hasGenericMethodArgs)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3107,6 +3107,9 @@
<data name="NotSupported_NonReflectedType" xml:space="preserve">
<value>Not supported in a non-reflected type.</value>
</data>
<data name="InvalidProgram_AsyncMethod" xml:space="preserve">
<value>Async methods with UnmanagedCallersOnlyAttribute are invalid.</value>
</data>
<data name="InvalidProgram_NonStaticMethod" xml:space="preserve">
<value>Non-static methods with UnmanagedCallersOnlyAttribute are invalid.</value>
</data>
Expand Down
23 changes: 21 additions & 2 deletions src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
6 changes: 6 additions & 0 deletions src/tests/Interop/COM/RuntimeAsync/RuntimeAsyncNative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
38 changes: 38 additions & 0 deletions src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Loading
Loading