Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken IDispatch.GetTypeInfo interop tests #3305

Closed
weltkante opened this issue May 19, 2020 · 10 comments · Fixed by #3315 or #3321
Closed

Broken IDispatch.GetTypeInfo interop tests #3305

weltkante opened this issue May 19, 2020 · 10 comments · Fixed by #3315 or #3321
Assignees
Labels
area-Interop test-bug Problem in test source code (most likely)

Comments

@weltkante
Copy link
Contributor

weltkante commented May 19, 2020

.NET Core Version:
Master with PR #3276 applied

Have you experienced this same bug with .NET Framework?:
unknown

Problem description:
The tests were flaky before, sometimes throwing ComException(E_FAIL). The update of xunit.stafact now is properly hosting everything in an WinForms STA thread and they suddenly seem to fail "reliably" with this error here.

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_AddressOfMember_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_AddressOfMember_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 23

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_CreateInstance_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_CreateInstance_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 39

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetDllEntry_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetDllEntry_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 81

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetFuncDesc_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetFuncDesc_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 123

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetIDsOfNames_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetIDsOfNames_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 159

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetMops_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetMops_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 196

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetRefTypeInfo_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_GetRefTypeInfo_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 236

System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_Invoke_Invoke_Success
System.Runtime.InteropServices.InvalidComObjectException : COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.
   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr ppUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
   at Interop.Oleaut32.IDispatch.GetTypeInfo(UInt32 iTInfo, UInt32 lcid, ITypeInfo& ppTInfo)
   at System.Windows.Forms.Primitives.Tests.Interop.Oleaut32.ITypeInfoTests.ITypeInfo_Invoke_Invoke_Success() in D:\projects\winforms\src\System.Windows.Forms.Primitives\tests\Interop\Oleaut32\ITypeInfoTests.cs:line 368

Expected behavior:
Tests pass or there is a reasonable explanation for the error

Minimal repro:
Run tests with PR #3276 applied

@weltkante
Copy link
Contributor Author

weltkante commented May 19, 2020

I can reproduce these exceptions inside the VS debugger, but I don't know how to diagnose this without further assistance.

Things I checked:

  • updated above tests to WinFormsFact and made sure they execute in STA
  • made sure WinForms was not calling any Marshal.ReleaseComObject or Marshal.FinalReleaseComObject APIs which in my experience can be common sources of this exception if the RCW is used after being released

What else can cause this exception? I have a dump taken from debugger here. If I can assist diagnosis in other ways feel free to make suggestions.

/cc @AaronRobinsonMSFT @JeremyKuhne for COM interop issues

@weltkante
Copy link
Contributor Author

weltkante commented May 19, 2020

I remembered that ITypeInfo can be finnicky and added Marshal.ReleaseComObject(typeInfo); to the end of each test, that seems to work around the problem.

I still don't see how letting the GC cleanup an RCW refcount can cause this particular exception though, is this something that could be a bug in the coreclr RCW finalizer and needs further investigation, or should we just ignore this and be working around by manually managing ITypeInfo RCW refcounts?

@RussKie RussKie added the test-bug Problem in test source code (most likely) label May 19, 2020
@RussKie RussKie added this to the 5.0 milestone May 19, 2020
@RussKie RussKie added the waiting-review This item is waiting on review by one or more members of team label May 19, 2020
@hughbe
Copy link
Contributor

hughbe commented May 20, 2020

I remember in #2603 (#2603 (comment)) we had some problems. Maybe they are realted?

@weltkante
Copy link
Contributor Author

weltkante commented May 20, 2020

Right, this is probably related to the linked comment. It'll probably mean we have to do manual RCW reference management to avoid the problem of automatic release, I'll do the corresponding PR.

I still want the opinion of @AaronRobinsonMSFT on whether this may be a race condition in the runtime that needs further inspection, or if we should ignore it and work around it.

@hughbe
Copy link
Contributor

hughbe commented May 20, 2020

I also made this a while ago: https://github.com/hughbe/Interop-Repro

Run StressTest.ps1 from the root of the repo

@weltkante
Copy link
Contributor Author

Having read through the whole linked thread it looks like this issue was exactly what happened before. The previous workaround was probably relying on xunit.stafact behavior, now that its updated the old workaround might no longer work. The correct workaround is to never cause the problematic situation, if you don't want to wind up individual processes for tests the easiest solution is manual RCW reference management.

Considering that this scenario already has been examined there's probably no desire to fix anything in classic COM interop. I'll be preparing the PR to do manual RCW reference management then, that should fix the issue reliably for the future.

@ghost ghost added the 🚧 work in progress Work that is current in progress label May 20, 2020
@AaronRobinsonMSFT
Copy link
Member

Sorry about missing this. @hughbe Yes, this issue is the same as #2603 (comment). This is a general problem with the XUnit framework and the STA for concurrent tests. @weltkante Your suggestion about manual Release seems reasonable to me.

@AaronRobinsonMSFT AaronRobinsonMSFT removed their assignment May 20, 2020
@ghost ghost removed the 🚧 work in progress Work that is current in progress label May 21, 2020
@RussKie RussKie removed this from the 5.0 milestone May 21, 2020
@RussKie RussKie removed the waiting-review This item is waiting on review by one or more members of team label May 21, 2020
@RussKie
Copy link
Member

RussKie commented May 21, 2020

Thank you all 🚀

@weltkante
Copy link
Contributor Author

weltkante commented May 21, 2020

Sorry, missed one ITypeInfo 😞 Want me to make another PR for that line or leave that for the nuget package update? Around 1 out of 10 runs fails locally so I missed it. Its definitely better than all tests failing constantly.

@RussKie
Copy link
Member

RussKie commented May 21, 2020

Let's fix it :)

@ghost ghost added 🚧 work in progress Work that is current in progress and removed 🚧 work in progress Work that is current in progress labels May 21, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Feb 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Interop test-bug Problem in test source code (most likely)
Projects
None yet
5 participants