dotnet / diagnostics

This repository contains the source code for various .NET Core runtime diagnostic tools and documents.
MIT License
1.18k stars 354 forks source link

SOS!do fails to display static fields value for types defined in System.Private.CoreLib.dll #280

Closed mikem8361 closed 5 years ago

mikem8361 commented 5 years ago

Moved from coreclr #https://github.com/dotnet/coreclr/issues/22248. Submitted by @chrisnas.

Repro:

  1. create a .NET Core console application
  2. use procdump -ma to generate a memory dump
  3. open the dump in WinDBG and load sos.dll (.loadby sos coreclr)
  4. enumerate type instances (!dumpheap -stat) and look for CultureInfo instances
  5. dump a CultureInfo instance: each static field has NOINIT as value
    
    00007fffc61fadf8  4000fa5      a30 ...ation.CultureInfo  0   shared           static s_userDefaultCulture
                                 >> Domain:Value  000001a5824a8010:NotInit  <<
    00007fffc61fadf8  4000fa6      a38 ...ation.CultureInfo  0   shared           static s_userDefaultUICulture
                                 >> Domain:Value  000001a5824a8010:NotInit  <<
    00007fffc61fadf8  4000fa7      a40 ...ation.CultureInfo  0   shared           static s_InvariantCultureInfo
                                 >> Domain:Value  000001a5824a8010:NotInit  <<

The same behavior occurs with string.Empty

**Investigation:**
The !do command ends up calling a few functions
[Strike.cs|DumpObj](https://github.com/dotnet/coreclr/blob/master/src/ToolBox/SOS/Strike/strike.cpp#L2011)
-> [Strike.cs|PrintObj](https://github.com/dotnet/coreclr/blob/master/src/ToolBox/SOS/Strike/strike.cpp#L1488)
-> [Util.cs|DisplayFields](https://github.com/dotnet/coreclr/blob/af46c514824aacd4d439eb1891d3d392c6894476/src/ToolBox/SOS/Strike/util.cpp#L1452)
-> [Util.cs|DisplaySharedStatic](https://github.com/dotnet/coreclr/blob/af46c514824aacd4d439eb1891d3d392c6894476/src/ToolBox/SOS/Strike/util.cpp#L1243)

This last function iterates on appdomains and calls [ClrDataAccess::GetDomainLocalModuleDataFromAppDomain](https://github.com/dotnet/coreclr/blob/af46c514824aacd4d439eb1891d3d392c6894476/src/debug/daccess/request.cpp#L3216) with a moduleID as an int (which is 32 bits even in x64)
This moduleID was an ULONG64 in DisplaySharedStatic but cast as an int

In .NET Framework, the moduleID seems to be an "index" like 1, 2 or 3 but in .NET Core, it looks like an address. The test on moduleID in GetDomainLocalModuleDataFromAppDomain will always fail:
if (appDomainAddr == 0 || **moduleID < 0** || pLocalModuleData == NULL)
        return E_INVALIDARG;

I have tried to change the interface to pass a CLRDATA_ADDRESS instead of an int 
(this change impacts src/debug/daccess/dacimpl.h, src/debug/daccess/request.cpp and src/pal/prebuilt/inc/sospriv.h)
but it is not really better: 
The code below the test does not make sense to me:
`ModuleIndex index = Module::IDToIndex(moduleID);`
static ModuleIndex IDToIndex(SIZE_T ModuleID)
{
    ModuleIndex index(**ModuleID >> 1**);
    return index;
}
Why dividing an "address" by 2 to get an "index"?

And the next line crashes when trying to GetModuleSlot
DomainLocalModule* pLocalModule = pAppDomain->GetDomainLocalBlock()->GetModuleSlot(index);

Note: this is the same problem as https://github.com/Microsoft/clrmd/issues/214 with ClrMD. 
mikem8361 commented 5 years ago

Possibly related to dotnet/diagnostics#50

mikem8361 commented 5 years ago

Fixed in Preview 9.