@@ -921,6 +921,7 @@ CordbProcess::CordbProcess(ULONG64 clrInstanceId,
921
921
m_unmanagedThreads(11),
922
922
#endif
923
923
m_appDomains(11),
924
+ m_sharedAppDomain(0),
924
925
m_steppers(11),
925
926
m_continueCounter(1),
926
927
m_flushCounter(0),
@@ -955,6 +956,7 @@ CordbProcess::CordbProcess(ULONG64 clrInstanceId,
955
956
m_iFirstPatch(0),
956
957
m_hHelperThread(NULL),
957
958
m_dispatchedEvent(DB_IPCE_DEBUGGER_INVALID),
959
+ m_pDefaultAppDomain(NULL),
958
960
m_hDacModule(hDacModule),
959
961
m_pDacPrimitives(NULL),
960
962
m_pEventChannel(NULL),
@@ -1057,6 +1059,8 @@ CordbProcess::~CordbProcess()
1057
1059
// We shouldn't still be in Cordb's list of processes. Unfortunately, our root Cordb object
1058
1060
// may have already been deleted b/c we're at the mercy of ref-counting, so we can't check.
1059
1061
1062
+ _ASSERTE(m_sharedAppDomain == NULL);
1063
+
1060
1064
m_processMutex.Destroy();
1061
1065
m_StopGoLock.Destroy();
1062
1066
@@ -1284,8 +1288,16 @@ void CordbProcess::NeuterChildren()
1284
1288
1285
1289
m_userThreads.NeuterAndClear(GetProcessLock());
1286
1290
1291
+ m_pDefaultAppDomain = NULL;
1292
+
1287
1293
// Frees per-appdomain left-side resources. See assumptions above.
1288
1294
m_appDomains.NeuterAndClear(GetProcessLock());
1295
+ if (m_sharedAppDomain != NULL)
1296
+ {
1297
+ m_sharedAppDomain->Neuter();
1298
+ m_sharedAppDomain->InternalRelease();
1299
+ m_sharedAppDomain = NULL;
1300
+ }
1289
1301
1290
1302
m_steppers.NeuterAndClear(GetProcessLock());
1291
1303
@@ -2294,10 +2306,10 @@ HRESULT CordbProcess::EnumerateHeapRegions(ICorDebugHeapSegmentEnum **ppRegions)
2294
2306
2295
2307
HRESULT CordbProcess::GetObject(CORDB_ADDRESS addr, ICorDebugObjectValue **ppObject)
2296
2308
{
2297
- return this->GetObjectInternal(addr, ppObject);
2309
+ return this->GetObjectInternal(addr, nullptr, ppObject);
2298
2310
}
2299
2311
2300
- HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, ICorDebugObjectValue **pObject)
2312
+ HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, CordbAppDomain* pAppDomainOverride, ICorDebugObjectValue **pObject)
2301
2313
{
2302
2314
HRESULT hr = S_OK;
2303
2315
@@ -2321,7 +2333,7 @@ HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, ICorDebugObjectValue
2321
2333
2322
2334
CordbAppDomain *cdbAppDomain = NULL;
2323
2335
CordbType *pType = NULL;
2324
- hr = GetTypeForObject(addr, &pType, &cdbAppDomain);
2336
+ hr = GetTypeForObject(addr, pAppDomainOverride, &pType, &cdbAppDomain);
2325
2337
2326
2338
if (SUCCEEDED(hr))
2327
2339
{
@@ -2429,7 +2441,7 @@ HRESULT CordbProcess::GetTypeForTypeID(COR_TYPEID id, ICorDebugType **ppType)
2429
2441
GetDAC()->GetObjectExpandedTypeInfoFromID(AllBoxed, VMPTR_AppDomain::NullPtr(), id, &data);
2430
2442
2431
2443
CordbType *type = 0;
2432
- hr = CordbType::TypeDataToType(GetAppDomain (), &data, &type);
2444
+ hr = CordbType::TypeDataToType(GetSharedAppDomain (), &data, &type);
2433
2445
2434
2446
if (SUCCEEDED(hr))
2435
2447
hr = type->QueryInterface(IID_ICorDebugType, (void**)ppType);
@@ -2557,7 +2569,7 @@ COM_METHOD CordbProcess::EnumerateLoaderHeapMemoryRegions(ICorDebugMemoryRangeEn
2557
2569
return hr;
2558
2570
}
2559
2571
2560
- HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbType **ppType, CordbAppDomain **pAppDomain)
2572
+ HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbAppDomain* pAppDomainOverride, CordbType **ppType, CordbAppDomain **pAppDomain)
2561
2573
{
2562
2574
VMPTR_AppDomain appDomain;
2563
2575
VMPTR_Module mod;
@@ -2566,7 +2578,11 @@ HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbType **ppType, C
2566
2578
HRESULT hr = E_FAIL;
2567
2579
if (GetDAC()->GetAppDomainForObject(addr, &appDomain, &mod, &domainAssembly))
2568
2580
{
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);
2570
2586
2571
2587
_ASSERTE(cdbAppDomain);
2572
2588
@@ -5353,6 +5369,19 @@ void CordbProcess::RawDispatchEvent(
5353
5369
}
5354
5370
_ASSERTE (pAppDomain != NULL);
5355
5371
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
+
5356
5385
// This will still maintain weak references so we could call Continue.
5357
5386
AddToNeuterOnContinueList(pAppDomain);
5358
5387
@@ -8688,23 +8717,19 @@ CordbAppDomain * CordbProcess::LookupOrCreateAppDomain(VMPTR_AppDomain vmAppDoma
8688
8717
return CacheAppDomain(vmAppDomain);
8689
8718
}
8690
8719
8691
- CordbAppDomain * CordbProcess::GetAppDomain ()
8720
+ CordbAppDomain * CordbProcess::GetSharedAppDomain ()
8692
8721
{
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)
8697
8723
{
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();
8703
8730
}
8704
8731
8705
- VMPTR_AppDomain vmAppDomain = GetDAC()->GetCurrentAppDomain();
8706
- appDomain = LookupOrCreateAppDomain(vmAppDomain);
8707
- return appDomain;
8732
+ return m_sharedAppDomain;
8708
8733
}
8709
8734
8710
8735
//---------------------------------------------------------------------------------------
@@ -8740,6 +8765,10 @@ CordbAppDomain * CordbProcess::CacheAppDomain(VMPTR_AppDomain vmAppDomain)
8740
8765
// The cache will take ownership.
8741
8766
m_appDomains.AddBaseOrThrow(pAppDomain);
8742
8767
8768
+ // If this assert fires, then it likely means the target is corrupted.
8769
+ TargetConsistencyCheck(m_pDefaultAppDomain == NULL);
8770
+ m_pDefaultAppDomain = pAppDomain;
8771
+
8743
8772
CordbAppDomain * pReturn = pAppDomain;
8744
8773
pAppDomain.ClearAndMarkDontNeuter();
8745
8774
@@ -15234,6 +15263,46 @@ HRESULT CordbProcess::IsReadyForDetach()
15234
15263
return S_OK;
15235
15264
}
15236
15265
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
+
15237
15306
// CordbProcess::LookupClass
15238
15307
// Looks up a previously constructed CordbClass instance without creating. May return NULL if the
15239
15308
// CordbClass instance doesn't exist.
0 commit comments