From: Elinor Fung <47805090+elinor-fung@users.noreply.github.com> Date: Tue, 28 Jul 2020 17:21:56 +0000 (-0700) Subject: Error on multiple calling conventions in modopts (#39809) X-Git-Tag: submit/tizen/20210909.063632~6379 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=50a999dd3597a33b62a7a1a1712c849e764d50e9;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Error on multiple calling conventions in modopts (#39809) --- diff --git a/src/coreclr/src/dlls/mscorrc/mscorrc.rc b/src/coreclr/src/dlls/mscorrc/mscorrc.rc index a50f742..3604420 100644 --- a/src/coreclr/src/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/src/dlls/mscorrc/mscorrc.rc @@ -182,6 +182,7 @@ BEGIN IDS_EE_NDIRECT_UNSUPPORTED_SIG "Method's type signature is not PInvoke compatible." IDS_EE_COM_UNSUPPORTED_SIG "Method's type signature is not Interop compatible." IDS_EE_COM_UNSUPPORTED_TYPE "The method returned a COM Variant type that is not Interop compatible." + IDS_EE_MULTIPLE_CALLCONV_UNSUPPORTED "Multiple unmanaged calling conventions are specified. Only a single calling convention is supported." IDS_EE_NDIRECT_BADNATL "Invalid PInvoke or UnmanagedFunctionPointer metadata format." IDS_EE_NDIRECT_BADNATL_CALLCONV "Invalid PInvoke or UnmanagedFunctionPointer calling convention." IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV "Invalid PInvoke calling convention. Vararg functions must use the cdecl calling convention." diff --git a/src/coreclr/src/dlls/mscorrc/resource.h b/src/coreclr/src/dlls/mscorrc/resource.h index 738b751..b78c5d8 100644 --- a/src/coreclr/src/dlls/mscorrc/resource.h +++ b/src/coreclr/src/dlls/mscorrc/resource.h @@ -43,6 +43,7 @@ #define IDS_EE_COM_UNSUPPORTED_SIG 0x170d #define IDS_EE_NOSYNCHRONIZED 0x170f #define IDS_EE_NDIRECT_BADNATL_THISCALL 0x1710 +#define IDS_EE_MULTIPLE_CALLCONV_UNSUPPORTED 0x1711 #define IDS_EE_LOAD_BAD_MAIN_SIG 0x1712 #define IDS_EE_COM_UNSUPPORTED_TYPE 0x1713 diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs index f549637..3d7dd28 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs @@ -508,6 +508,7 @@ namespace Internal.JitInterface if (!signature.HasEmbeddedSignatureData || signature.GetEmbeddedSignatureData() == null) return false; + bool found = false; foreach (EmbeddedSignatureData data in signature.GetEmbeddedSignatureData()) { if (data.kind != EmbeddedSignatureDataKind.OptionalCustomModifier) @@ -524,25 +525,28 @@ namespace Internal.JitInterface if (defType.Namespace != "System.Runtime.CompilerServices") continue; - // Take the first recognized calling convention in metadata. - switch (defType.Name) + // Look for a recognized calling convention in metadata. + CorInfoCallConv? callConvLocal = defType.Name switch { - case "CallConvCdecl": - callConv = CorInfoCallConv.CORINFO_CALLCONV_C; - return true; - case "CallConvStdcall": - callConv = CorInfoCallConv.CORINFO_CALLCONV_STDCALL; - return true; - case "CallConvFastcall": - callConv = CorInfoCallConv.CORINFO_CALLCONV_FASTCALL; - return true; - case "CallConvThiscall": - callConv = CorInfoCallConv.CORINFO_CALLCONV_THISCALL; - return true; + "CallConvCdecl" => CorInfoCallConv.CORINFO_CALLCONV_C, + "CallConvStdcall" => CorInfoCallConv.CORINFO_CALLCONV_STDCALL, + "CallConvFastcall" => CorInfoCallConv.CORINFO_CALLCONV_FASTCALL, + "CallConvThiscall" => CorInfoCallConv.CORINFO_CALLCONV_THISCALL, + _ => null + }; + + if (callConvLocal.HasValue) + { + // Error if there are multiple recognized calling conventions + if (found) + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramMultipleCallConv, MethodBeingCompiled); + + callConv = callConvLocal.Value; + found = true; } } - return false; + return found; } private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* sig) diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs index 00286ea..d9d3de4 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs @@ -36,6 +36,7 @@ namespace Internal.TypeSystem InvalidProgramNonStaticMethod, InvalidProgramGenericMethod, InvalidProgramNonBlittableTypes, + InvalidProgramMultipleCallConv, // BadImageFormatException BadImageFormatGeneric, diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Properties/Resources.resx b/src/coreclr/src/tools/Common/TypeSystem/Common/Properties/Resources.resx index 3681459..b0efd67 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/Properties/Resources.resx +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Properties/Resources.resx @@ -174,7 +174,10 @@ UnmanagedCallersOnly attribute specified on method with non-blittable parameters '{0}' + + Multiple unmanaged calling conventions are specified. Only a single calling convention is supported. + The format of a DLL or executable being loaded is invalid - \ No newline at end of file + diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.cs index 9ab806e..094ade1 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.cs @@ -42,6 +42,12 @@ namespace Internal.TypeSystem } [System.Diagnostics.DebuggerHidden] + public static void ThrowInvalidProgramException(ExceptionStringID id) + { + throw new TypeSystemException.InvalidProgramException(id); + } + + [System.Diagnostics.DebuggerHidden] public static void ThrowInvalidProgramException(ExceptionStringID id, MethodDesc method) { throw new TypeSystemException.InvalidProgramException(id, Format.Method(method)); diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs index 9311369..17836ca 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs @@ -138,6 +138,11 @@ namespace Internal.TypeSystem { } + internal InvalidProgramException(ExceptionStringID id) + : base(id) + { + } + internal InvalidProgramException() : base(ExceptionStringID.InvalidProgramDefault) { diff --git a/src/coreclr/src/vm/dllimport.cpp b/src/coreclr/src/vm/dllimport.cpp index 2fd2fef..752fbd0 100644 --- a/src/coreclr/src/vm/dllimport.cpp +++ b/src/coreclr/src/vm/dllimport.cpp @@ -2955,7 +2955,8 @@ namespace _In_ Module *pModule, _In_ PCCOR_SIGNATURE pSig, _In_ ULONG cSig, - _Out_ CorPinvokeMap *pPinvokeMapOut) + _Out_ CorPinvokeMap *pPinvokeMapOut, + _Out_ UINT *errorResID) { CONTRACTL { @@ -2966,7 +2967,7 @@ namespace CONTRACTL_END CorUnmanagedCallingConvention callConvMaybe; - HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(pModule, pSig, cSig, &callConvMaybe); + HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(pModule, pSig, cSig, &callConvMaybe, errorResID); if (hr != S_OK) return hr; @@ -2992,10 +2993,12 @@ void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg) callConv = GetDefaultCallConv(bIsVarArg); CorPinvokeMap sigCallConv = (CorPinvokeMap)0; - HRESULT hr = GetUnmanagedPInvokeCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv); + UINT errorResID; + HRESULT hr = GetUnmanagedPInvokeCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv, &errorResID); if (FAILED(hr)) { - SetError(IDS_EE_NDIRECT_BADNATL); //Bad metadata format + // Set an error message specific to P/Invokes or UnmanagedFunction for bad format. + SetError(hr == COR_E_BADIMAGEFORMAT ? IDS_EE_NDIRECT_BADNATL : errorResID); } // Do the same WinAPI to StdCall or CDecl for the signature calling convention as well. We need @@ -6859,7 +6862,12 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD) if (callConv == IMAGE_CEE_CS_CALLCONV_UNMANAGED) { CorUnmanagedCallingConvention callConvMaybe; - if (S_OK == MetaSig::TryGetUnmanagedCallingConventionFromModOpt(pVASigCookie->pModule, signature.GetRawSig(), signature.GetRawSigLen(), &callConvMaybe)) + UINT errorResID; + HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(pVASigCookie->pModule, signature.GetRawSig(), signature.GetRawSigLen(), &callConvMaybe, &errorResID); + if (FAILED(hr)) + COMPlusThrowHR(hr, errorResID); + + if (hr == S_OK) { callConv = callConvMaybe; } diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index 09c0776..e955b3d 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -515,7 +515,12 @@ CEEInfo::ConvToJitSig( static_assert_no_msg(CORINFO_CALLCONV_FASTCALL == (CorInfoCallConv)IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL); CorUnmanagedCallingConvention callConvMaybe; - if (S_OK == MetaSig::TryGetUnmanagedCallingConventionFromModOpt(module, pSig, cbSig, &callConvMaybe)) + UINT errorResID; + HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(module, pSig, cbSig, &callConvMaybe, &errorResID); + if (FAILED(hr)) + COMPlusThrowHR(hr, errorResID); + + if (hr == S_OK) { sigRet->callConv = (CorInfoCallConv)callConvMaybe; } diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index 61bbbb8..ee42a4e 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -5267,7 +5267,8 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt( _In_ Module *pModule, _In_ PCCOR_SIGNATURE pSig, _In_ ULONG cSig, - _Out_ CorUnmanagedCallingConvention *callConvOut) + _Out_ CorUnmanagedCallingConvention *callConvOut, + _Out_ UINT *errorResID) { CONTRACTL { @@ -5276,6 +5277,7 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt( FORBID_FAULT; MODE_ANY; PRECONDITION(callConvOut != NULL); + PRECONDITION(errorResID != NULL); } CONTRACTL_END @@ -5285,13 +5287,17 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt( _ASSERTE(pWalk <= pSig + cSig); *callConvOut = (CorUnmanagedCallingConvention)0; + bool found = false; while ((pWalk < (pSig + cSig)) && ((*pWalk == ELEMENT_TYPE_CMOD_OPT) || (*pWalk == ELEMENT_TYPE_CMOD_REQD))) { BOOL fIsOptional = (*pWalk == ELEMENT_TYPE_CMOD_OPT); pWalk++; if (pWalk + CorSigUncompressedDataSize(pWalk) > pSig + cSig) - return E_FAIL; // Bad formatting + { + *errorResID = BFA_BAD_SIGNATURE; + return COR_E_BADIMAGEFORMAT; // Bad formatting + } mdToken tk; pWalk += CorSigUncompressToken(pWalk, &tk); @@ -5320,16 +5326,23 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt( for (const auto &callConv : knownCallConvs) { - // Take the first recognized calling convention in metadata. + // Look for a recognized calling convention in metadata. if (::strcmp(typeName, callConv.name) == 0) { + // Error if there are multiple recognized calling conventions + if (found) + { + *errorResID = IDS_EE_MULTIPLE_CALLCONV_UNSUPPORTED; + return COR_E_INVALIDPROGRAM; + } + *callConvOut = callConv.value; - return S_OK; + found = true; } } } - return S_FALSE; + return found ? S_OK : S_FALSE; } //--------------------------------------------------------------------------------------- diff --git a/src/coreclr/src/vm/siginfo.hpp b/src/coreclr/src/vm/siginfo.hpp index 64c9341..7f3fa8b 100644 --- a/src/coreclr/src/vm/siginfo.hpp +++ b/src/coreclr/src/vm/siginfo.hpp @@ -781,20 +781,20 @@ class MetaSig //---------------------------------------------------------- // Gets the unmanaged calling convention by reading any modopts. - // If there are multiple modopts specifying recognized calling - // conventions, the first one that is found in the metadata wins. - // Note: the order in the metadata is the reverse of that in IL. // // Returns: - // E_FAIL - Signature had an invalid format // S_OK - Calling convention was read from modopt // S_FALSE - Calling convention was not read from modopt + // COR_E_BADIMAGEFORMAT - Signature had an invalid format + // COR_E_INVALIDPROGRAM - Program is considered invalid (more + // than one calling convention specified) //---------------------------------------------------------- static HRESULT TryGetUnmanagedCallingConventionFromModOpt( _In_ Module *pModule, _In_ PCCOR_SIGNATURE pSig, _In_ ULONG cSig, - _Out_ CorUnmanagedCallingConvention *callConvOut); + _Out_ CorUnmanagedCallingConvention *callConvOut, + _Out_ UINT *errorResID); static CorUnmanagedCallingConvention GetDefaultUnmanagedCallingConvention() { diff --git a/src/tests/baseservices/callconvs/TestCallingConventions.cs b/src/tests/baseservices/callconvs/TestCallingConventions.cs index 935e401..fe42b69 100644 --- a/src/tests/baseservices/callconvs/TestCallingConventions.cs +++ b/src/tests/baseservices/callconvs/TestCallingConventions.cs @@ -89,8 +89,10 @@ unsafe class Program { // Multiple modopts with calling conventions Console.WriteLine($" -- unmanaged modopt(stdcall) modopt(cdecl)"); - int b = CallFunctionPointers.CallUnmanagedIntInt_ModOptStdcall_ModOptCdecl(cbCdecl, a); - Assert.AreEqual(expected, b); + var ex = Assert.Throws( + () => CallFunctionPointers.CallUnmanagedIntInt_ModOptStdcall_ModOptCdecl(cbCdecl, a), + "Multiple modopts with calling conventions should fail"); + Assert.AreEqual("Multiple unmanaged calling conventions are specified. Only a single calling convention is supported.", ex.Message); } { @@ -165,8 +167,10 @@ unsafe class Program { // Multiple modopts with calling conventions Console.WriteLine($" -- unmanaged modopt(stdcall) modopt(cdecl)"); - var b = CallFunctionPointers.CallUnmanagedCharChar_ModOptStdcall_ModOptCdecl(cbCdecl, a); - Assert.AreEqual(expected, b); + var ex = Assert.Throws( + () => CallFunctionPointers.CallUnmanagedCharChar_ModOptStdcall_ModOptCdecl(cbCdecl, a), + "Multiple modopts with calling conventions should fail"); + Assert.AreEqual("Multiple unmanaged calling conventions are specified. Only a single calling convention is supported.", ex.Message); } {