RCW Finalizer Access Violation

I use COM interoperability to create a managed plugin in an unmanaged application using VS2012 / .NET 4.5 / Win8.1. It seems that all the interop files go fine, but when I close the application, I get an MDA exception telling me that AV happened when the COM objects that RCW held during Finalization were released.

This is the call stack:

clr.dll!MdaReportAvOnComRelease::ReportHandledException() + 0x91 bytes clr.dll!**SafeRelease_OnException**() + 0x55 bytes clr.dll!SafeReleasePreemp() + 0x312d5f bytes clr.dll!RCW::ReleaseAllInterfaces() + 0xf3 bytes clr.dll!RCW::ReleaseAllInterfacesCallBack() + 0x4f bytes clr.dll!RCW::Cleanup() + 0x24 bytes clr.dll!RCWCleanupList::ReleaseRCWListRaw() + 0x16 bytes clr.dll!RCWCleanupList::ReleaseRCWListInCorrectCtx() + 0x9c bytes clr.dll!RCWCleanupList::CleanupAllWrappers() + 0x2cd1b6 bytes clr.dll!RCWCache::ReleaseWrappersWorker() + 0x277 bytes clr.dll!AppDomain::ReleaseRCWs() + 0x120cb2 bytes clr.dll!ReleaseRCWsInCaches() + 0x3f bytes clr.dll!InnerCoEEShutDownCOM() + 0x46 bytes clr.dll!WKS::GCHeap::**FinalizerThreadStart**() + 0x229 bytes clr.dll!Thread::intermediateThreadProc() + 0x76 bytes kernel32.dll!BaseThreadInitThunk() + 0xd bytes ntdll.dll!RtlUserThreadStart() + 0x1d bytes 

I assume that the application has already destroyed its COM objects, from which some links were passed to the managed plug-in, and the IUnknown :: Release call made by RCW makes it go with an arrow.

In the output window (VS), I clearly see that the application has already begun unloading some of them dlls.

 'TestHost.exe': Unloaded 'C:\Windows\System32\msls31.dll' 'TestHost.exe': Unloaded 'C:\Windows\System32\usp10.dll' 'TestHost.exe': Unloaded 'C:\Windows\System32\riched20.dll' 'TestHost.exe': Unloaded 'C:\Windows\System32\version.dll' First-chance exception at 0x00000001400cea84 in VST3PluginTestHost.exe: 0xC0000005: Access violation reading location 0xffffffffffffffff. First-chance exception at 0x00000001400cea84 in VST3PluginTestHost.exe: 0xC0000005: Access violation reading location 0xffffffffffffffff. Managed Debugging Assistant 'ReportAvOnComRelease' has detected a problem in 'C:\Program Files\Steinberg\VST3PluginTestHost\VST3PluginTestHost.exe'. Additional Information: An exception was caught but handled while releasing a COM interface pointer through Marshal.Release or Marshal.ReleaseComObject or implicitly after the corresponding RuntimeCallableWrapper was garbage collected. This is the result of a user refcount error or other problem with a COM object Release. Make sure refcounts are managed properly. The COM interface pointer original vtable pointer was 0x406975a8. While these types of exceptions are caught by the CLR, they can still lead to corruption and data loss so if possible the issue causing the exception should be addressed 

So even though I would manage my life and write a ComReference class that calls Marshal.ReleaseComObject. This did not work correctly, and after reading it, I have to agree that calling Marshal.ReleaseComObject in a script where links are passed freely is not a good idea. Marshal .ReleaseComObject considered dangerous

So the question is: is there a way to manage this situation so as not to cause AV when exiting the host application?

+7
c # visual-studio-2012 access-violation com-interop rcw
source share
2 answers

There are three real solutions to this problem, and I believe that interpreting the article “Marshall.ReleaseComObject is considered dangerous” as “Do not use Marshall.ReleaseComObject” can be misleading. Your takeaway can just as easily "not split RCWs freely."

Your three decisions:

1: Change the execution of your host application to unload plugins before it unloads itself. This is easier said than done. If the host process plug-in system includes a shutdown event, this would be a good place to solve this problem. All of your RCW-enabled services should free them during shutdown.

2: Use Marshall.ReleaseComObject in a template like Dispose (), ensuring that objects are only stored in a local area, similar to the block used. This is straightforward to implement, allows you to release the responses of COM links and, as a rule, a very good first approach.

3: Use a broker for a COM object that can transfer references to counted instances of RCW and then release these objects when no one is using them. Ensure that each consumer of these objects is cleaned before unloading the application.

Option # 2 works fine until you store / use links to managed RCW. I would use # 2 until you determined that your COM object has high activation costs and that caching / sharing matters.

+2
source share

This is a problem with counting links to COM. Your object has Release() d from its own code with refcount = 1, it is destroyed, then the CLR comes and tries to Release() it. You need to keep track of when the link count goes wrong. It crashes in the CLR because it performs a cleanup after the completion of its own code.

The first step is to track the type of object that is not being counted properly. I did this by running gflags.exe in my .exe and turning on "User Mode Stack gflags.exe ". A full bunch of pages can also help.

Run the application in windbg . Run .symfix . Run bp clr!SafeReleasePreemp "r rcx; gc"; g bp clr!SafeReleasePreemp "r rcx; gc"; g to register interface pointers. When it fails, the previous log entry should contain an interface pointer that has already been destroyed. Run !heap -p -a [address of COM pointer] and it will print the stack where it was released.

If you're out of luck, this will not work right away, and the interface pointer that causes the problems will not be the last log. If you can run your own COM in a Debug configuration, this may help.

MS created the RCW header . m_pIdentity interest are members of m_pIdentity (offset 0x88 by x64) and m_aInterfaceEntries (offset 0x8 by x64). RCW is at @rdx when entering SafeReleasePreemp

The next step is to repeat with breakpoints in the interface :: AddRef, Interface :: QueryInterface and Interface :: Release to see which one is incompatible. _ATL_DEBUG_INTERFACES can help if you use ATL.

0
source share

All Articles