Open
Description
Description
Consider the following code:
[GeneratedComInterface, Guid("427CE02F-515A-4338-BE30-F70DA3ADAEC1")]
public unsafe partial interface IRoot
{
void MyMethod0();
}
[GeneratedComInterface, Guid("1AEE856E-6501-43C8-843B-8210B57DFD27")]
public unsafe partial interface ItfA : IRoot
{
void MyMethod1();
}
[GeneratedComInterface, Guid("3264857C-BB23-418D-9528-1E4226F2FEA4")]
public unsafe partial interface ItfB : IRoot
{
void MyMethod2();
}
when IRoot is defined int the same assembly it works.
However when it is defined in another assembly, I get:
CSC : warning CS8785: Generator 'ComInterfaceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'An item with the same key has already been added.'.
Detailed msbuild output:
CSC : warning CS8785: Generator 'ComInterfaceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'An item with the same key has already been added.'.
1> System.ArgumentException: An item with the same key has already been added.
1> at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
1> at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
1> at Microsoft.Interop.ComInterfaceContext.GetContexts(ImmutableArray`1 data, CancellationToken _)
1> at Microsoft.CodeAnalysis.TransformNode`2.UpdateStateTable(Builder builder, NodeStateTable`1 previousTable, CancellationToken cancellationToken)
Debugging this shows:
Reproduction Steps
see above
Expected behavior
no exception raised
Actual behavior
see description the following exception is raised System.ArgumentException: An item with the same key has already been added.
Regression?
No response
Known Workarounds
No response
Configuration
No response
Other information
No response
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
No status
Activity
dotnet-policy-service commentedon Jan 28, 2025
Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.
AaronRobinsonMSFT commentedon Jan 28, 2025
@jkoritzinsky @jtschuster This seems odd. The number of interfaces that require other implementations shouldn't matter. Actually is this one of the issues we talked about where the base interface is in another assembly?
m-celikba commentedon Jan 28, 2025
@AaronRobinsonMSFT
If the base interface is in another assembly and only one interface inherits from it, it works.
If the base interface is in another assembly and more than one interface inherits from it, it fails with ArgumentException
jkoritzinsky commentedon Jan 28, 2025
This is a real bug in the "different aseembly" limited support we added.
Basically, that loop is the only place we import the base interfaces into our view. We should change that to do a try-add instead of a throwing Add.
m-celikba commentedon Jan 28, 2025
@jkoritzinsky I have a local fix. I'd like to move on locally with this fix.
I can build the generator project but have 2 problems: the assembly version numbers are messed up and I'm wondering what's the best way to override one of the runtime dll (in this case the generator dll) in my projects.
Where can I learn more about these ?
jkoritzinsky commentedon Jan 28, 2025
There's no good mechanism to override a generator dll shipped with the sdk with a local one. You would have to add some custom MSBuild targets to remove the one provided by the SDK and add your own.
m-celikba commentedon Jan 29, 2025
@jkoritzinsky @jtschuster there's another issue. Consider my example above.
when IRoot is in the same assembly as ItfA, the vtable length in CreateManagedVirtualFunctionTable() for ITfA has size 3+1+1=5.
when IRoot is in a different assembly than ItfA, the vtable length in CreateManagedVirtualFunctionTable() for ITfA has size 3+1=4.
It looks like the vtable is missing room for the base interface IRoot's methods.
(in the line void** vtable = (void**)global::System.Runtime.CompilerServices.RuntimeHelpers.AllocateTypeAssociatedMemory).
The vtable indices are correct though.
This causes a buffer overrun as the code tries to write to a smaller array.
Please let me know if you want me to file another more detailed bug.
m-celikba commentedon Jan 30, 2025
I should have said that the previous buffer overflow issue happens when/if the original issue is fixed.
If inheriting source generated COM interfaces from interfaces in another assembly is supported (I know there's a warning but as long as you know what you are doing this is a proper use case), then it should just work.
If this is not possible, then another simple way could be to allow passing a vtable offset.
[GeneratedComInterface(VTableOffset=<number_of_methods_on_the_base_only>)]