@@ -921,6 +921,7 @@ CordbProcess::CordbProcess(ULONG64 clrInstanceId,
921921 m_unmanagedThreads(11),
922922#endif
923923 m_appDomains(11),
924+ m_sharedAppDomain(0),
924925 m_steppers(11),
925926 m_continueCounter(1),
926927 m_flushCounter(0),
@@ -955,6 +956,7 @@ CordbProcess::CordbProcess(ULONG64 clrInstanceId,
955956 m_iFirstPatch(0),
956957 m_hHelperThread(NULL),
957958 m_dispatchedEvent(DB_IPCE_DEBUGGER_INVALID),
959+ m_pDefaultAppDomain(NULL),
958960 m_hDacModule(hDacModule),
959961 m_pDacPrimitives(NULL),
960962 m_pEventChannel(NULL),
@@ -1057,6 +1059,8 @@ CordbProcess::~CordbProcess()
10571059 // We shouldn't still be in Cordb's list of processes. Unfortunately, our root Cordb object
10581060 // may have already been deleted b/c we're at the mercy of ref-counting, so we can't check.
10591061
1062+ _ASSERTE(m_sharedAppDomain == NULL);
1063+
10601064 m_processMutex.Destroy();
10611065 m_StopGoLock.Destroy();
10621066
@@ -1284,8 +1288,16 @@ void CordbProcess::NeuterChildren()
12841288
12851289 m_userThreads.NeuterAndClear(GetProcessLock());
12861290
1291+ m_pDefaultAppDomain = NULL;
1292+
12871293 // Frees per-appdomain left-side resources. See assumptions above.
12881294 m_appDomains.NeuterAndClear(GetProcessLock());
1295+ if (m_sharedAppDomain != NULL)
1296+ {
1297+ m_sharedAppDomain->Neuter();
1298+ m_sharedAppDomain->InternalRelease();
1299+ m_sharedAppDomain = NULL;
1300+ }
12891301
12901302 m_steppers.NeuterAndClear(GetProcessLock());
12911303
@@ -2294,10 +2306,10 @@ HRESULT CordbProcess::EnumerateHeapRegions(ICorDebugHeapSegmentEnum **ppRegions)
22942306
22952307HRESULT CordbProcess::GetObject(CORDB_ADDRESS addr, ICorDebugObjectValue **ppObject)
22962308{
2297- return this->GetObjectInternal(addr, ppObject);
2309+ return this->GetObjectInternal(addr, nullptr, ppObject);
22982310}
22992311
2300- HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, ICorDebugObjectValue **pObject)
2312+ HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, CordbAppDomain* pAppDomainOverride, ICorDebugObjectValue **pObject)
23012313{
23022314 HRESULT hr = S_OK;
23032315
@@ -2321,7 +2333,7 @@ HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, ICorDebugObjectValue
23212333
23222334 CordbAppDomain *cdbAppDomain = NULL;
23232335 CordbType *pType = NULL;
2324- hr = GetTypeForObject(addr, &pType, &cdbAppDomain);
2336+ hr = GetTypeForObject(addr, pAppDomainOverride, &pType, &cdbAppDomain);
23252337
23262338 if (SUCCEEDED(hr))
23272339 {
@@ -2429,7 +2441,7 @@ HRESULT CordbProcess::GetTypeForTypeID(COR_TYPEID id, ICorDebugType **ppType)
24292441 GetDAC()->GetObjectExpandedTypeInfoFromID(AllBoxed, VMPTR_AppDomain::NullPtr(), id, &data);
24302442
24312443 CordbType *type = 0;
2432- hr = CordbType::TypeDataToType(GetAppDomain (), &data, &type);
2444+ hr = CordbType::TypeDataToType(GetSharedAppDomain (), &data, &type);
24332445
24342446 if (SUCCEEDED(hr))
24352447 hr = type->QueryInterface(IID_ICorDebugType, (void**)ppType);
@@ -2557,7 +2569,7 @@ COM_METHOD CordbProcess::EnumerateLoaderHeapMemoryRegions(ICorDebugMemoryRangeEn
25572569 return hr;
25582570}
25592571
2560- HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbType **ppType, CordbAppDomain **pAppDomain)
2572+ HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbAppDomain* pAppDomainOverride, CordbType **ppType, CordbAppDomain **pAppDomain)
25612573{
25622574 VMPTR_AppDomain appDomain;
25632575 VMPTR_Module mod;
@@ -2566,7 +2578,11 @@ HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbType **ppType, C
25662578 HRESULT hr = E_FAIL;
25672579 if (GetDAC()->GetAppDomainForObject(addr, &appDomain, &mod, &domainAssembly))
25682580 {
2569- CordbAppDomain *cdbAppDomain = appDomain.IsNull() ? GetAppDomain() : LookupOrCreateAppDomain(appDomain);
2581+ if (pAppDomainOverride)
2582+ {
2583+ appDomain = pAppDomainOverride->GetADToken();
2584+ }
2585+ CordbAppDomain *cdbAppDomain = appDomain.IsNull() ? GetSharedAppDomain() : LookupOrCreateAppDomain(appDomain);
25702586
25712587 _ASSERTE(cdbAppDomain);
25722588
@@ -5353,6 +5369,19 @@ void CordbProcess::RawDispatchEvent(
53535369 }
53545370 _ASSERTE (pAppDomain != NULL);
53555371
5372+ // See if this is the default AppDomain exiting. This should only happen very late in
5373+ // the shutdown cycle, and so we shouldn't do anything significant with m_pDefaultDomain==NULL.
5374+ // We should try and remove m_pDefaultDomain entirely since we can't count on it always existing.
5375+ if (pAppDomain == m_pDefaultAppDomain)
5376+ {
5377+ m_pDefaultAppDomain = NULL;
5378+ }
5379+
5380+ // Update any threads which were last seen in this AppDomain. We don't
5381+ // get any notification when a thread leaves an AppDomain, so our idea
5382+ // of what AppDomain the thread is in may be out of date.
5383+ UpdateThreadsForAdUnload( pAppDomain );
5384+
53565385 // This will still maintain weak references so we could call Continue.
53575386 AddToNeuterOnContinueList(pAppDomain);
53585387
@@ -8688,23 +8717,19 @@ CordbAppDomain * CordbProcess::LookupOrCreateAppDomain(VMPTR_AppDomain vmAppDoma
86888717 return CacheAppDomain(vmAppDomain);
86898718}
86908719
8691- CordbAppDomain * CordbProcess::GetAppDomain ()
8720+ CordbAppDomain * CordbProcess::GetSharedAppDomain ()
86928721{
8693- // Return the one and only app domain
8694- HASHFIND find;
8695- CordbAppDomain* appDomain = m_appDomains.FindFirst(&find);
8696- if (appDomain != NULL)
8722+ if (m_sharedAppDomain == NULL)
86978723 {
8698- const ULONG appDomainId = 1; // DefaultADID in appdomain.hpp
8699- ULONG32 id;
8700- HRESULT hr = appDomain->GetID(&id);
8701- TargetConsistencyCheck(SUCCEEDED(hr) && id == appDomainId);
8702- return appDomain;
8724+ CordbAppDomain *pAD = new CordbAppDomain(this, VMPTR_AppDomain::NullPtr());
8725+ if (InterlockedCompareExchangeT<CordbAppDomain*>(&m_sharedAppDomain, pAD, NULL) != NULL)
8726+ {
8727+ delete pAD;
8728+ }
8729+ m_sharedAppDomain->InternalAddRef();
87038730 }
87048731
8705- VMPTR_AppDomain vmAppDomain = GetDAC()->GetCurrentAppDomain();
8706- appDomain = LookupOrCreateAppDomain(vmAppDomain);
8707- return appDomain;
8732+ return m_sharedAppDomain;
87088733}
87098734
87108735//---------------------------------------------------------------------------------------
@@ -8740,6 +8765,10 @@ CordbAppDomain * CordbProcess::CacheAppDomain(VMPTR_AppDomain vmAppDomain)
87408765 // The cache will take ownership.
87418766 m_appDomains.AddBaseOrThrow(pAppDomain);
87428767
8768+ // If this assert fires, then it likely means the target is corrupted.
8769+ TargetConsistencyCheck(m_pDefaultAppDomain == NULL);
8770+ m_pDefaultAppDomain = pAppDomain;
8771+
87438772 CordbAppDomain * pReturn = pAppDomain;
87448773 pAppDomain.ClearAndMarkDontNeuter();
87458774
@@ -15234,6 +15263,46 @@ HRESULT CordbProcess::IsReadyForDetach()
1523415263 return S_OK;
1523515264}
1523615265
15266+
15267+ /*
15268+ * Look for any thread which was last seen in the specified AppDomain.
15269+ * The CordbAppDomain object is about to be neutered due to an AD Unload
15270+ * So the thread must no longer be considered to be in that domain.
15271+ * Note that this is a workaround due to the existence of the (possibly incorrect)
15272+ * cached AppDomain value. Ideally we would remove the cached value entirely
15273+ * and there would be no need for this.
15274+ *
15275+ * @dbgtodo: , appdomain: We should remove CordbThread::m_pAppDomain in the V3 architecture.
15276+ * If we need the thread's current domain, we should get it accurately with DAC.
15277+ */
15278+ void CordbProcess::UpdateThreadsForAdUnload(CordbAppDomain * pAppDomain)
15279+ {
15280+ INTERNAL_API_ENTRY(this);
15281+
15282+ // If we're doing an AD unload then we should have already seen the ATTACH
15283+ // notification for the default domain.
15284+ //_ASSERTE( m_pDefaultAppDomain != NULL );
15285+ // @dbgtodo appdomain: fix Default domain invariants with DAC-izing Appdomain work.
15286+
15287+ RSLockHolder lockHolder(GetProcessLock());
15288+
15289+ CordbThread* t;
15290+ HASHFIND find;
15291+
15292+ // We don't need to prepopulate here (to collect LS state) because we're just updating RS state.
15293+ for (t = m_userThreads.FindFirst(&find);
15294+ t != NULL;
15295+ t = m_userThreads.FindNext(&find))
15296+ {
15297+ if( t->GetAppDomain() == pAppDomain )
15298+ {
15299+ // This thread cannot actually be in this AppDomain anymore (since it's being
15300+ // unloaded). Reset it to point to the default AppDomain
15301+ t->m_pAppDomain = m_pDefaultAppDomain;
15302+ }
15303+ }
15304+ }
15305+
1523715306// CordbProcess::LookupClass
1523815307// Looks up a previously constructed CordbClass instance without creating. May return NULL if the
1523915308// CordbClass instance doesn't exist.
0 commit comments