Skip to content

Commit f05acbb

Browse files
[release/10.0] Look up the correct MethodTable on COM methods. (#121512)
Backport of #121431 to release/10.0 /cc @AaronRobinsonMSFT ## Customer Impact - [x] Customer reported - [ ] Found internally How a COM server is activated can obscure how we determine the `IID` of a COM interface method. This matters in scenarios involving `ISupportErrorInfo`. A user reported this in #121252. ## Regression - [x] Yes - [ ] No This is a regression from .NET 9. It was introduced in #117690. ## Testing Tests were updated to validate this behavior. ## Risk Low. This only impacts COM scenarios involving `ISupportErrorInfo`. --------- Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
1 parent db6324d commit f05acbb

File tree

16 files changed

+46
-27
lines changed

16 files changed

+46
-27
lines changed

src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,14 +1357,18 @@ internal static Exception GetHRExceptionObject(int hr)
13571357
}
13581358

13591359
#if FEATURE_COMINTEROP
1360-
internal static Exception GetCOMHRExceptionObject(int hr, IntPtr pCPCMD, IntPtr pUnk)
1360+
internal static unsafe Exception GetCOMHRExceptionObject(int hr, IntPtr pCPCMD, IntPtr pUnk)
13611361
{
1362-
RuntimeMethodHandle handle = RuntimeMethodHandle.FromIntPtr(pCPCMD);
1363-
RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(handle.GetMethodInfo());
1362+
Debug.Assert(pCPCMD != IntPtr.Zero);
1363+
MethodTable* interfaceType = GetComInterfaceFromMethodDesc(pCPCMD);
1364+
RuntimeType declaringType = RuntimeTypeHandle.GetRuntimeType(interfaceType);
13641365
Exception ex = Marshal.GetExceptionForHR(hr, declaringType.GUID, pUnk)!;
13651366
ex.InternalPreserveStackTrace();
13661367
return ex;
13671368
}
1369+
1370+
[MethodImpl(MethodImplOptions.InternalCall)]
1371+
private static extern unsafe MethodTable* GetComInterfaceFromMethodDesc(IntPtr pCPCMD);
13681372
#endif // FEATURE_COMINTEROP
13691373

13701374
[ThreadStatic]

src/coreclr/vm/ecalllist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ FCFuncStart(gStubHelperFuncs)
352352
FCFuncElement("SetLastError", StubHelpers::SetLastError)
353353
FCFuncElement("ClearLastError", StubHelpers::ClearLastError)
354354
#ifdef FEATURE_COMINTEROP
355+
FCFuncElement("GetComInterfaceFromMethodDesc", StubHelpers::GetComInterfaceFromMethodDesc)
355356
FCFuncElement("GetCOMIPFromRCW", StubHelpers::GetCOMIPFromRCW)
356357
#endif // FEATURE_COMINTEROP
357358
FCFuncElement("CalcVaListSize", StubHelpers::CalcVaListSize)

src/coreclr/vm/stubhelpers.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ FORCEINLINE static IUnknown* GetCOMIPFromRCW_GetTargetFromRCWCache(SOleTlsData*
266266
return NULL;
267267
}
268268

269+
FCIMPL1(MethodTable*, StubHelpers::GetComInterfaceFromMethodDesc, MethodDesc* pMD)
270+
{
271+
FCALL_CONTRACT;
272+
_ASSERTE(pMD != NULL);
273+
return CLRToCOMCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;
274+
}
275+
FCIMPLEND
276+
269277
//==================================================================================================================
270278
// The GetCOMIPFromRCW helper exists in four specialized versions to optimize CLR->COM perf. Please be careful when
271279
// changing this code as one of these methods is executed as part of every CLR->COM call so every instruction counts.

src/coreclr/vm/stubhelpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class StubHelpers
2626
//-------------------------------------------------------
2727

2828
#ifdef FEATURE_COMINTEROP
29+
static FCDECL1(MethodTable*, GetComInterfaceFromMethodDesc, MethodDesc* pMD);
2930
static FCDECL3(IUnknown*, GetCOMIPFromRCW, Object* pSrcUNSAFE, MethodDesc* pMD, void **ppTarget);
3031
#endif // FEATURE_COMINTEROP
3132

src/tests/Interop/COM/NETClients/ComDisabled/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static int TestEntryPoint()
2222

2323
try
2424
{
25-
var server = (Server.Contract.Servers.NumericTesting)new Server.Contract.Servers.NumericTestingClass();
25+
var server = new Server.Contract.Servers.NumericTesting();
2626
}
2727
catch (NotSupportedException) when (OperatingSystem.IsWindows())
2828
{

src/tests/Interop/COM/NETClients/Events/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static void Validate_BasicCOMEvent()
2020
{
2121
Console.WriteLine($"{nameof(Validate_BasicCOMEvent)}...");
2222

23-
var eventTesting = (EventTesting)new EventTestingClass();
23+
var eventTesting = new EventTesting();
2424

2525
// Verify event handler subscription
2626

@@ -57,7 +57,7 @@ static void Validate_COMEventViaComAwareEventInfo()
5757
{
5858
Console.WriteLine($"{nameof(Validate_COMEventViaComAwareEventInfo)}...");
5959

60-
var eventTesting = (EventTesting)new EventTestingClass();
60+
var eventTesting = new EventTesting();
6161

6262
// Verify event handler subscription
6363

src/tests/Interop/COM/NETClients/IDispatch/Program.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class Program
1919
{
2020
static void Validate_Numeric_In_ReturnByRef()
2121
{
22-
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
22+
var dispatchTesting = new DispatchTesting();
2323

2424
byte b1 = 1;
2525
byte b2 = b1;
@@ -74,7 +74,7 @@ static private bool EqualByBound(double expected, double actual)
7474

7575
static void Validate_Float_In_ReturnAndUpdateByRef()
7676
{
77-
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
77+
var dispatchTesting = new DispatchTesting();
7878

7979
float a = .1f;
8080
float b = .2f;
@@ -91,7 +91,7 @@ static void Validate_Float_In_ReturnAndUpdateByRef()
9191

9292
static void Validate_Double_In_ReturnAndUpdateByRef()
9393
{
94-
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
94+
var dispatchTesting = new DispatchTesting();
9595

9696
double a = .1;
9797
double b = .2;
@@ -114,7 +114,7 @@ static int GetErrorCodeFromHResult(int hresult)
114114

115115
static void Validate_Exception()
116116
{
117-
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
117+
var dispatchTesting = new DispatchTesting();
118118

119119
int errorCode = 1127;
120120
string resultString = errorCode.ToString("x");
@@ -174,15 +174,15 @@ static void Validate_Exception()
174174
static void Validate_StructNotSupported()
175175
{
176176
Console.WriteLine($"IDispatch with structs not supported...");
177-
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
177+
var dispatchTesting = new DispatchTesting();
178178

179179
var input = new HFA_4() { x = 1f, y = 2f, z = 3f, w = 4f };
180180
Assert.Throws<NotSupportedException>(() => dispatchTesting.DoubleHVAValues(ref input));
181181
}
182182

183183
static void Validate_LCID_Marshaled()
184184
{
185-
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
185+
var dispatchTesting = new DispatchTesting();
186186
CultureInfo oldCulture = CultureInfo.CurrentCulture;
187187
CultureInfo newCulture = new CultureInfo("es-ES", false);
188188
try
@@ -200,7 +200,7 @@ static void Validate_LCID_Marshaled()
200200

201201
static void Validate_Enumerator()
202202
{
203-
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
203+
var dispatchTesting = new DispatchTesting();
204204
var expected = System.Linq.Enumerable.Range(0, 10);
205205

206206
{
@@ -251,7 +251,7 @@ static System.Collections.Generic.IEnumerable<int> ConvertEnumerable(System.Coll
251251

252252
static void Validate_ValueCoerce_ReturnToManaged()
253253
{
254-
var dispatchCoerceTesting = (DispatchCoerceTesting)new DispatchCoerceTestingClass();
254+
var dispatchCoerceTesting = new DispatchCoerceTesting();
255255

256256
Console.WriteLine($"Calling {nameof(DispatchCoerceTesting.ReturnToManaged)} ...");
257257

src/tests/Interop/COM/NETClients/IInspectable/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class Program
1818
{
1919
static void Validate_IInspectable()
2020
{
21-
var server = (InspectableTesting)new InspectableTestingClass();
21+
var server = new InspectableTesting();
2222
Assert.Throws<PlatformNotSupportedException>(() => _ = (IInspectableTesting2)server);
2323
}
2424

src/tests/Interop/COM/NETClients/Licensing/Program.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ static void ActivateLicensedObject()
2323
Console.WriteLine($"Calling {nameof(ActivateLicensedObject)}...");
2424

2525
// Validate activation
26-
var licenseTesting = (LicenseTesting)new LicenseTestingClass();
26+
var licenseTesting = new LicenseTesting();
2727

2828
// Validate license denial
2929
licenseTesting.SetNextDenyLicense(true);
3030
try
3131
{
32-
var tmp = (LicenseTesting)new LicenseTestingClass();
32+
var tmp = new LicenseTesting();
3333
Assert.Fail("Activation of licensed class should fail");
3434
}
3535
catch (COMException e)
@@ -86,7 +86,7 @@ static void ActivateUnderDesigntimeContext()
8686
LicenseManager.CurrentContext = new MockLicenseContext(typeof(LicenseTestingClass), LicenseUsageMode.Designtime);
8787
LicenseManager.CurrentContext.SetSavedLicenseKey(typeof(LicenseTestingClass), licKey);
8888

89-
var licenseTesting = (LicenseTesting)new LicenseTestingClass();
89+
var licenseTesting = new LicenseTesting();
9090

9191
// During design time the IClassFactory::CreateInstance will be called - no license
9292
Assert.Null(licenseTesting.GetLicense());
@@ -111,7 +111,7 @@ static void ActivateUnderRuntimeContext()
111111
LicenseManager.CurrentContext = new MockLicenseContext(typeof(LicenseTestingClass), LicenseUsageMode.Runtime);
112112
LicenseManager.CurrentContext.SetSavedLicenseKey(typeof(LicenseTestingClass), licKey);
113113

114-
var licenseTesting = (LicenseTesting)new LicenseTestingClass();
114+
var licenseTesting = new LicenseTesting();
115115

116116
// During runtime the IClassFactory::CreateInstance2 will be called with license from context
117117
Assert.Equal(licKey, licenseTesting.GetLicense());

src/tests/Interop/COM/NETClients/MiscTypes/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ private static void ValidationTests()
8787
{
8888
Console.WriteLine($"Running {nameof(ValidationTests)} ...");
8989

90-
var miscTypeTesting = (Server.Contract.Servers.MiscTypesTesting)new Server.Contract.Servers.MiscTypesTestingClass();
90+
var miscTypeTesting = new Server.Contract.Servers.MiscTypesTesting();
9191

9292
Console.WriteLine("-- Primitives <=> VARIANT...");
9393
{
@@ -226,7 +226,7 @@ private static void ValidateNegativeTests()
226226
{
227227
Console.WriteLine($"Running {nameof(ValidateNegativeTests)} ...");
228228

229-
var miscTypeTesting = (Server.Contract.Servers.MiscTypesTesting)new Server.Contract.Servers.MiscTypesTestingClass();
229+
var miscTypeTesting = new Server.Contract.Servers.MiscTypesTesting();
230230

231231
Console.WriteLine("-- DispatchWrapper with non-IDispatch object <=> VARIANT...");
232232
{

0 commit comments

Comments
 (0)