Skip to content

Commit 97d83e7

Browse files
Fix MarshalAs IID parameter index parsing (#128364)
Fixes native AOT outerloop runs that are currently broken. NativeAOT could assert while parsing valid `MarshalAs` metadata emitted for COM interface parameters using `IidParameterIndex`, leaving unread bytes in the marshal descriptor blob. - **Parser** - Consume optional `IidParameterIndex` payloads for COM interface native types: - `IUnknown` - `IDispatch` - `Interface` - Keep existing behavior of using only the native type in NativeAOT. - **Regression coverage** - Added TypeSystem coverage for descriptors like: ```csharp [MarshalAs(UnmanagedType.Interface, IidParameterIndex = 0)] out object value ``` - Covered `Interface`, `IUnknown`, and `IDispatch` marshal descriptors. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com> Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com>
1 parent 0f580f7 commit 97d83e7

4 files changed

Lines changed: 45 additions & 0 deletions

File tree

src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,18 @@ public MarshalAsDescriptor ParseMarshalAsDescriptor()
612612
}
613613
}
614614
break;
615+
case NativeTypeKind.IUnknown:
616+
case NativeTypeKind.IDispatch:
617+
case NativeTypeKind.Intf:
618+
{
619+
if (_reader.RemainingBytes != 0)
620+
{
621+
// There's nobody to consume COM marshalling, so let's just parse the data
622+
// to avoid asserting later.
623+
_reader.ReadCompressedInteger();
624+
}
625+
}
626+
break;
615627
case NativeTypeKind.CustomMarshaler:
616628
{
617629
// Read typelib guid

src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Marshalling.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,5 +179,23 @@ public class ClassWithSequentialInt64Base : SequentialInt64Base
179179
public int i;
180180
}
181181

182+
public class MethodsWithMarshalAs
183+
{
184+
public void IUnknownWithIidParameterIndex(object iid, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 0)] out object value)
185+
{
186+
value = new object();
187+
}
188+
189+
public void IDispatchWithIidParameterIndex(object iid, [MarshalAs(UnmanagedType.IDispatch, IidParameterIndex = 0)] out object value)
190+
{
191+
value = new object();
192+
}
193+
194+
public void InterfaceWithIidParameterIndex(object iid, [MarshalAs(UnmanagedType.Interface, IidParameterIndex = 0)] out object value)
195+
{
196+
value = new object();
197+
}
198+
}
199+
182200
#endregion
183201
}

src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Platform.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ public enum UnmanagedType
214214
public sealed class MarshalAsAttribute : Attribute
215215
{
216216
public MarshalAsAttribute(UnmanagedType unmanagedType) { }
217+
public int IidParameterIndex { get; set; }
217218
}
218219

219220
public sealed class ComImportAttribute : Attribute

src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/MarshalUtilsTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,19 @@ public void IsBlittableType_TypeWithEmptyBase_ReturnsTrue(string className)
8080
TypeDesc classWithEmptyBase = _testModule.GetType("Marshalling"u8, Encoding.UTF8.GetBytes(className));
8181
Assert.True(MarshalUtils.IsBlittableType(classWithEmptyBase));
8282
}
83+
84+
[Theory]
85+
[InlineData("IUnknownWithIidParameterIndex", NativeTypeKind.IUnknown)]
86+
[InlineData("IDispatchWithIidParameterIndex", NativeTypeKind.IDispatch)]
87+
[InlineData("InterfaceWithIidParameterIndex", NativeTypeKind.Intf)]
88+
public void MarshalAsComInterface_WithIidParameterIndex_ParsesCorrectly(string methodName, NativeTypeKind nativeType)
89+
{
90+
MetadataType marshallingType = _testModule.GetType("Marshalling"u8, "MethodsWithMarshalAs"u8);
91+
MethodDesc marshalAsMethod = marshallingType.GetMethod(Encoding.UTF8.GetBytes(methodName), null);
92+
93+
ParameterMetadata parameter = marshalAsMethod.GetParameterMetadata()[1];
94+
95+
Assert.Equal(nativeType, parameter.MarshalAsDescriptor.Type);
96+
}
8397
}
8498
}

0 commit comments

Comments
 (0)