Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Conversation

janvorli
Copy link
Member

@janvorli janvorli commented Nov 9, 2018

This change is relatively straightforward:

  • Move the ComCallWrapper cache from AppDomain to LoaderAllocator, including the lifetime management logic and update the ComCallWrapper code here and there to be LoaderAllocator bound.
  • Move the interop data hash table from AppDomain to LoaderAllocator
  • Modify DispatchMemberInfo to use handles allocated by LoaderAllocator, which lead to some refactoring of the code that accessed the handle.

Closes #20164

@janvorli janvorli added this to the 3.0 milestone Nov 9, 2018
@janvorli janvorli self-assigned this Nov 9, 2018
@janvorli janvorli requested a review from jkotas November 9, 2018 22:27
@jkotas
Copy link
Member

jkotas commented Nov 10, 2018

Do we need any tests for this?

m_pDefaultContext = NULL;
#ifdef FEATURE_COMINTEROP
m_pComCallWrapperCache = NULL;
m_pRCWCache = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the RCW caches fine wrt. unloading?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They (or I should rather say it as there is only one in one app domain) don't cause any issues while unloading. It seems that the only reason why they were per AppDomain was the isolation (based on the doc I was able to find in BOTR) and they seem to be cleaned on a regular basis.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.g. RCW has InterfaceEntry m_aInterfaceEntries[INTERFACE_ENTRY_CACHE_SIZE]; in it. This array contains MethodTable pointers. What guarantees that none of these pointers point to MethodTable that got unloaded?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me look into that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GCToEEInterface::AfterGcScanRoots calls AppDomain::DetachRCWs which loops over all entries in the RCW cache and marks all RCWs whose exposed objects were not promoted as detached.
They are then cleaned in RCWCleanupList::CleanupAllWrappers() which is called from SyncBlockCache::CleanupSyncBlocks() which in turn is called from Thread::DoExtraWorkForFinalizer(). This happens right before the call to SystemDomain::System()->ProcessDelayedUnloadLoaderAllocators(), so the RCWs don't outlive the related MethodTable instances.
So unless I am missing something, it seems we should be good.

//
if (pClassMT->Collectible())
{
COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleCOM"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete the NotSupported_CollectibleCOM message?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for spotting that.

@janvorli
Copy link
Member Author

We already have a couple of coreclr tests for that. Interop/MarshalAPI/IUnknown and tests in Interop/COM.

@davidwrighton
Copy link
Member

I'd like to see us have a subset of "interesting" tests for collectible loadercontexts that execute during normal test runs, and don't require some sort of special test pass.

@davidwrighton
Copy link
Member

It feels like there may be some issue with WinRT. are we sure that no managed WinRT type could be exposed from a collectible type?

@janvorli
Copy link
Member Author

@davidwrighton what kind of problems with WinRT do you expect if we exposed managed WinRT objects from collectible types?

@janvorli janvorli force-pushed the enable-collectible-com-interop branch from ece8b8d to f56a91d Compare November 16, 2018 02:05
@janvorli janvorli force-pushed the enable-collectible-com-interop branch from f56a91d to 66ecc14 Compare November 20, 2018 01:21
@janvorli
Copy link
Member Author

@dotnet-bot test CentOS7.1 x64 Checked Innerloop Build and Test please
@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test please

@janvorli
Copy link
Member Author

@dotnet-bot test Windows_NT arm64 Cross Checked Innerloop Build and Test please

@janvorli
Copy link
Member Author

@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test (Jit - TieredCompilation=0) please

@janvorli
Copy link
Member Author

@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test (Jit - TieredCompilation=0) please

@janvorli janvorli force-pushed the enable-collectible-com-interop branch from b30aafa to 7aa7836 Compare November 21, 2018 16:57
@janvorli
Copy link
Member Author

@jkotas I believe I've addressed feedback and responded to question. I have also added two unloadability tests. Could you please take another look?

@jkotas
Copy link
Member

jkotas commented Nov 21, 2018

Is it the right design to neuter all COM object references on unload?

AppDomains needed because of they have done forceful unload regardless of whether somebody was holding reference to inside of the AppDomain or not. We are not doing forceful unload here.

I would think that COM object references should be just like any other object references. As long as there are any alive, the load context should stay alive. Once all of them are gone, the load context can be unloaded.

Thoughts?

@janvorli
Copy link
Member Author

@jkotas We don't do that. If there are COM references, they keep the LoaderAllocator alive.

// we have a template, create a wrapper and initialize from the template
// alloc wrapper, aligned 32 bytes
if (pWrapperCache->IsDomainUnloading())
if (pWrapperCache->IsLoaderAllocatorUnloading())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f there are COM references, they keep the LoaderAllocator alive.

So why do we need to throw AppDomainUnloadedException here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for other purpose. After the unloading is initiated, this code prevents new CCW creation. But the ones that were created before that still work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regular P/Invoke interop is allowed even after the unloading is initialized. Why do we want to disallow COM?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion on this. This was the way the AppDomain behaved after the Unload was initiated on them, so I have kept it. But I don't think there would be any issue if we removed this check.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have doubts about this. I do not think we should be blocking any interop when the stuff is unloading.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppDomains had to do it because of they would not be able to forcefully unload otherwise. ALCs do not have forceful unload, so they do not need it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let's remove this check.

@jkotas
Copy link
Member

jkotas commented Nov 26, 2018

I have pulled this down to do some ad-hoc testing to see how well it works. I am hitting a crashes when I load&unload a trivial program that uses COM in a loop.

Repro: https://gist.github.com/jkotas/db2536c79dd61899781406af5316037f

Result:

Assert failure(PID 17364 [0x000043d4], Thread: 4896 [0x1320]): Consistency check failed: AV in clr at this callstack:
------
CORECLR! CodeFragmentHeap::RealAllocAlignedMem + 0x79 (0x00007ffe`85237e65)
CORECLR! Precode::AllocateTemporaryEntryPoints + 0xDD (0x00007ffe`85853589)
CORECLR! MethodDescChunk::CreateTemporaryEntryPoints + 0x69 (0x00007ffe`855ba6b5)
CORECLR! MethodDescChunk::EnsureTemporaryEntryPointsCreated + 0x108 (0x00007ffe`855baa00)
CORECLR! MethodDesc::SetTemporaryEntryPoint + 0x21 (0x00007ffe`855c75e9)
CORECLR! ILStubCache::CreateNewMethodDesc + 0x574 (0x00007ffe`858ac418)
CORECLR! ILStubCache::GetStubMethodDesc + 0x434 (0x00007ffe`858ae74c)
CORECLR! NDirect::GetStubMethodDesc + 0x83B (0x00007ffe`855395d3)
CORECLR! ILStubCreatorHelper::HolderEnter + 0x32 (0x00007ffe`8553a8c2)
CORECLR! CreateInteropILStub + 0x53F (0x00007ffe`8552be57)
CORECLR! NDirect::CreateCLRToNativeILStub + 0x6EA (0x00007ffe`8552a492)

* Remove collectible check from IsTypeVisibleFromCom. That fixes three
  new COM interop tests
* Add collectible check to GetComClassFactory when we check for
  unsupported interop with WinRT
* Fix two contracts
Add two tests to test COM unloadability:
* One for using native COM server from managed COM client
* One for using managed COM objects from native client
It was missing copying the native server dll to the test folder.
@janvorli janvorli force-pushed the enable-collectible-com-interop branch from 3d43ccf to 4e53c70 Compare November 29, 2018 10:23
@janvorli
Copy link
Member Author

@dotnet-bot test CentOS7.1 x64 Checked Innerloop Build and Test please

@janvorli
Copy link
Member Author

@dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test please
@dotnet-bot test Ubuntu arm Cross Checked Innerloop Build and Test please
@dotnet-bot test Ubuntu arm Cross Checked crossgen_comparison Build and Test please
@dotnet-bot test Ubuntu arm Cross Checked no_tiered_compilation_innerloop Build and Test please
@dotnet-bot test Ubuntu arm Cross Checked no_tiered_compilation_innerloop Build and Test please
@dotnet-bot test Ubuntu x64 Checked CoreFX Tests

@janvorli
Copy link
Member Author

@dotnet-bot test Ubuntu arm Cross Release crossgen_comparison Build and Test please
@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test please
@dotnet-bot test Ubuntu16.04 arm64 Cross Checked Innerloop Build and Test please
@dotnet-bot test Ubuntu16.04 arm64 Cross Checked no_tiered_compilation_innerloop Build and Test please
@dotnet-bot test Windows_NT arm Cross Checked Innerloop Build and Test please
@dotnet-bot test Windows_NT arm Cross Debug Innerloop Build please
@dotnet-bot test Windows_NT arm64 Cross Checked Innerloop Build and Test please
@dotnet-bot test Windows_NT arm64 Cross Debug Innerloop Build please
@dotnet-bot test Windows_NT x64 Checked CoreFX Tests please
@dotnet-bot test Windows_NT x64 full_opt ryujit CoreCLR Perf Tests Correctness please
@dotnet-bot test Windows_NT x64 Checked Innerloop Build and Test (Jit - TieredCompilation=0) please
@dotnet-bot test Windows_NT x86 Checked Innerloop Build and Test (Jit - TieredCompilation=0) please

@janvorli
Copy link
Member Author

@dotnet-bot test Windows_NT x86 Release Innerloop Build and Test please

@janvorli
Copy link
Member Author

@dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test please

The NETClientPrimitives is disabled there too.
@AaronRobinsonMSFT
Copy link
Member

There is some flakyness with this on x86 and ARM. I am unable to reproduce this locally nor is it occurring on any other architectures. I will be fixing the warnings and disabling the test and fixing this tomorrow. See #21294.

@AaronRobinsonMSFT
Copy link
Member

@dotnet-bot test Windows_NT arm Cross Debug Innerloop Build please
@dotnet-bot test Windows_NT x86 Checked Innerloop Build and Test (Jit - TieredCompilation=0) please

@janvorli
Copy link
Member Author

@jkotas I've added the new IUnknownTestInALC that serves as a regression test for the ILStubCache issue and also verified that your example works fine. Do you think we can merge this change now?

@jkotas
Copy link
Member

jkotas commented Nov 30, 2018

I think so. I do not see any other issues. I am sure there are more, but they are hard to find.

@janvorli
Copy link
Member Author

janvorli commented Dec 1, 2018

@jkotas I've removed the check for the LoaderAllocator unloading and all the stuff that become obsolete due to that.

@janvorli janvorli merged commit 4c461d7 into dotnet:master Dec 1, 2018
@janvorli janvorli deleted the enable-collectible-com-interop branch December 1, 2018 09:31
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
* Enable COM interop for collectible classes

* Modify DispatchInfo to use LoaderAllocator handles

The DispatchMemberInfo was using global handles to refer to the managed
MemberInfo instances. That doesn't work with unloadability.
This change modifies it to use handles allocated from LoaderAllocator.

* Disable COM interop for WinRT types

* Remove collectible check from IsTypeVisibleFromCom. That fixes three
  new COM interop tests
* Add collectible check to GetComClassFactory when we check for
  unsupported interop with WinRT

* Add COM unloadability tests

Add two tests to test COM unloadability:
* One for using native COM server from managed COM client
* One for using managed COM objects from native client

* Add unloading test for IUnknownTest

* Disable NETClientPrimitivesInALC on Win ARM

The NETClientPrimitives is disabled there too.



Commit migrated from dotnet/coreclr@4c461d7
AaronRobinsonMSFT added a commit to AaronRobinsonMSFT/runtime that referenced this pull request Oct 27, 2022
This is a regression from NETFX with the introduction
of collectable assemblies in .NET Core 3.1 (dotnet/coreclr#20919).
AaronRobinsonMSFT added a commit to dotnet/runtime that referenced this pull request Oct 27, 2022
This is a regression from NETFX with the introduction
of collectable assemblies in .NET Core 3.1 (dotnet/coreclr#20919).
github-actions bot pushed a commit to dotnet/runtime that referenced this pull request Oct 27, 2022
This is a regression from NETFX with the introduction
of collectable assemblies in .NET Core 3.1 (dotnet/coreclr#20919).
carlossanlop pushed a commit to dotnet/runtime that referenced this pull request Nov 3, 2022
This is a regression from NETFX with the introduction
of collectable assemblies in .NET Core 3.1 (dotnet/coreclr#20919).

Co-authored-by: Aaron Robinson <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants