microsoft / clrmd

Microsoft.Diagnostics.Runtime is a set of APIs for introspecting processes and dumps.
MIT License
1.05k stars 255 forks source link

COMException in CacheNativeMethods.Util.EnableDisablePrivilege #1041

Closed pharring closed 1 year ago

pharring commented 2 years ago

Using nuget package Microsoft.Diagnostics.Runtime 2.2.332302 I have a test that's failing in Azure Pipelines with the following callstack:

at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
at Microsoft.Diagnostics.Runtime.Windows.CacheNativeMethods.Util.EnableDisablePrivilege(String PrivilegeName, Boolean enable)
at Microsoft.Diagnostics.Runtime.Windows.CachedMemoryReader..ctor(ImmutableArray`1 segments, String dumpPath, FileStream stream, Int64 maxCacheSize, CacheTechnology cacheTechnology, Int32 pointerSize, Boolean leaveOpen)
at Microsoft.Diagnostics.Runtime.Windows.Minidump..ctor(String displayName, Stream stream, CacheOptions cacheOptions, Boolean leaveOpen)
at Microsoft.Diagnostics.Runtime.MinidumpReader..ctor(String displayName, Stream stream, CacheOptions cacheOptions, Boolean leaveOpen)
at Microsoft.Diagnostics.Runtime.DataTarget.LoadDump(String displayName, Stream stream, CacheOptions cacheOptions, Boolean leaveOpen)
at Microsoft.Diagnostics.Runtime.DataTarget.LoadDump(String filePath, CacheOptions cacheOptions)
at Microsoft.DiagnosticServices.SnapshotDecompiler.Minidump.SnapshotParser.Parse() in \src\SnapshotDecompiler\Microsoft.DiagnosticServices.SnapshotDecompiler\MinidumpParser\SnapshotParser.cs:line 26

The exception meesage is: System.Runtime.InteropServices.COMException : The handle is invalid. (0x80070006 (E_HANDLE))

This is an x86 process loading an x86 memory dump.

The CachedMemoryReader constructor is trying to enable the SeLockMemoryPrivilege. However, for whatever reason, that's not available to x86 processes on the Azure Pipeline machine.

CachedMemoryReader has fallback code to handle the case when you can't get that privilege:

if ((CacheTechnology == CacheTechnology.AWE) &&
                CacheNativeMethods.Util.EnableDisablePrivilege("SeLockMemoryPrivilege", enable: true))
{
   // If we have the ability to lock physical memory in memory and the user has requested we use AWE, then do so, for best performance
}
else
{
   // We can't add the lock memory privilege, so just fall back on our ArrayPool/MemoryMappedFile based cache 
   ...
}

Unfortuantely, the COMException thrown from EnableDisablePrivilege thwarts the fallback test. The CachedMemoryReader probably needs a try/catch around the call to EnableDisablePrivilege:

if ((CacheTechnology == CacheTechnology.AWE) && TryEnableLockMemoryPrivilege())
{
   // If we have the ability to lock physical memory in memory and the user has requested we use AWE, then do so, for best performance
}
else
{
   // We can't add the lock memory privilege, so just fall back on our ArrayPool/MemoryMappedFile based cache 
   ...
}

static bool TryEnableLockMemoryPrivilege()
{
    try
    {
        return CacheNativeMethods.Util.EnableDisablePrivilege("SeLockMemoryPrivilege", enable: true);
    }
    catch (COMException)
    {
        return false;
    }
}
pharring commented 2 years ago

Adding

new CacheOptions { UseOSMemoryFeatures = false }

to the LoadDump method works around it by disabling AWE.

leculver commented 1 year ago

I've fixed this as of ClrMD 2.3. We shouldn't be throwing in a bool returning method.

I also made AWE features opt-in instead of opt-out to reduce how sharp of an edge this is.