Repository: dotnet/runtime
File: src/coreclr/vm/dllimport.cpp (C++)

Code before:
{
    bool HasSuppressGCTransitionAttribute(_In_ MethodDesc* pMD)
    {
        LIMITED_METHOD_CONTRACT;

        HRESULT hr = pMD->GetCustomAttribute(
            WellKnownAttribute::SuppressGCTransition,
            nullptr,
            nullptr);
        return hr == S_OK;
    }

    bool TryGetCallingConventionFromPInvokeMetadata(_In_ MethodDesc* pMD, _Out_ CorInfoCallConvExtension* callConv)
    {
        CONTRACTL
        {
            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;


        HRESULT hr = pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, NULL /*pszImportName*/, NULL /*pmrImportDLL*/);
        if (FAILED(hr))
            return false;

        callConvLocal = GetCallConvValueForPInvokeCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask));
        if (callConvLocal != CallConvWinApiSentinel)
        {
            *callConv = callConvLocal;
            return true;
        }

        return false;
    }

    bool TryGetCallingConventionFromUnmanagedFunctionPointer(_In_ MethodTable* pMT, _Out_ CorInfoCallConvExtension* callConv)
    {
        CONTRACTL
        {
            STANDARD_VM_CHECK;
            PRECONDITION(pMT != NULL);
            PRECONDITION(pMT->IsDelegate());
            PRECONDITION(callConv != NULL);

Review comment (bug):
Replacing the runtime check with a PRECONDITION is incorrect. The removed runtime check at lines 3064 (if pMD->IsAsyncMethod() ThrowHR) was a necessary validation that throws COR_E_NOTSUPPORTED for async methods. PRECONDITION checks are typically only active in debug builds and are meant for validating programming contracts, not for runtime validation. The caller GetCallingConvention_IgnoreErrors does not validate that methods are not async before calling this function. This could allow async P/Invoke methods to proceed unchecked in release builds, leading to undefined behavior instead of a proper exception. The runtime check should be retained, similar to how DllImportInit (line 2783) and GetILStubForCalli (line 6087) handle async methods.

Code after:
    {
        LIMITED_METHOD_CONTRACT;

        HRESULT hr = pMD->GetCustomAttribute(
            WellKnownAttribute::SuppressGCTransition,
            nullptr,
            nullptr);
        return hr == S_OK;
    }

    bool TryGetCallingConventionFromPInvokeMetadata(_In_ MethodDesc* pMD, _Out_ CorInfoCallConvExtension* callConv)
    {
        CONTRACTL
        {
            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;


        HRESULT hr = pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, NULL /*pszImportName*/, NULL /*pmrImportDLL*/);
        if (FAILED(hr))
            return false;

        callConvLocal = GetCallConvValueForPInvokeCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask));
        if (callConvLocal != CallConvWinApiSentinel)
        {
            *callConv = callConvLocal;
            return true;
        }

        return false;
    }

    bool TryGetCallingConventionFromUnmanagedFunctionPointer(_In_ MethodTable* pMT, _Out_ CorInfoCallConvExtension* callConv)
    {
        CONTRACTL
        {
            STANDARD_VM_CHECK;
            PRECONDITION(pMT != NULL);
            PRECONDITION(pMT->IsDelegate());
            PRECONDITION(callConv != NULL);
        }
        CONTRACTL_END;