7

I am using the CLR Memory Diagnostics library to get the stack trace of all threads in a running process:

        var result = new Dictionary<int, string[]>();

        var pid = Process.GetCurrentProcess().Id;

        using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive))
        {
            string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation();
            var runtime = dataTarget.CreateRuntime(dacLocation); //throws exception

            foreach (var t in runtime.Threads)
            {
                result.Add(
                    t.ManagedThreadId,
                    t.StackTrace.Select(f =>
                    {
                        if (f.Method != null)
                        {
                            return f.Method.Type.Name + "." + f.Method.Name;
                        }

                        return null;
                    }).ToArray()
                );
            }
        }

I got this code from here and it seems to be working for others, but it throws an exception for me on the indicated line, with the message This runtime is not initialized and contains no data.

dacLocation is set as C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll

Community
  • 1
  • 1
Drake
  • 2,679
  • 4
  • 45
  • 88
  • 4
    My crystal ball says that you have .NET 4.6 installed. This code currently dies on the eternal DAC version number misery, the 4.6 version of the DAC is 4.6.81.0. Looks like Microsoft switched to "semantic versioning". Not something ClrMD expects, it needs to find build number 10000 or greater to use the V45Runtime wrapper class. No obvious workaround that I can see, hacking the version number didn't work either, Microsoft needs to update ClrMD to handle 4.6 as well. – Hans Passant Jul 26 '15 at 09:37
  • See related sample code here: http://stackoverflow.com/questions/10315862/get-list-of-threads/35558240#35558240. – Contango Feb 22 '16 at 16:07

2 Answers2

10

ClrMD currently doesn't support .NET 4.6. There's an open pull request on GitHub that fixes this issue with just one line. You can of course clone the project and build your own ClrMD that doesn't exhibit this issue.

Or, I can share a temporary hack that I've been using over the last few weeks:

public static ClrRuntime CreateRuntimeHack(this DataTarget target, string dacLocation, int major, int minor)
{
    string dacFileNoExt = Path.GetFileNameWithoutExtension(dacLocation);
    if (dacFileNoExt.Contains("mscordacwks") && major == 4 && minor >= 5)
    {
        Type dacLibraryType = typeof(DataTarget).Assembly.GetType("Microsoft.Diagnostics.Runtime.DacLibrary");
        object dacLibrary = Activator.CreateInstance(dacLibraryType, target, dacLocation);
        Type v45RuntimeType = typeof(DataTarget).Assembly.GetType("Microsoft.Diagnostics.Runtime.Desktop.V45Runtime");
        object runtime = Activator.CreateInstance(v45RuntimeType, target, dacLibrary);
        return (ClrRuntime)runtime;
    }
    else
    {
        return target.CreateRuntime(dacLocation);
    }
}

I know, it's horrible, and relies on Reflection. But at least it works for now, and you don't have to change the code.

Sasha Goldshtein
  • 3,499
  • 22
  • 35
  • 1
    The updated version Microsoft.Diagnostics.Runtime.dll 0.08.31 15.10.2015 01:48 can get the Runtime but it fails with a NullReferenceException in runtime.GetHeap() in HasArrayComponentMethoTables.get. Now the correct V45Runtime instance is used but it still breaks. At least this is the case with 4.6.96.0. Is this a known issue? – Alois Kraus Dec 15 '15 at 14:02
6

You can fix this issue by downloading the latest version of the Microsoft.Diagnostics.Runtime.dll (v0.8.31-beta): https://www.nuget.org/packages/Microsoft.Diagnostics.Runtime

Version v0.8.31-beta marked a number of features obsolete, so as Alois Kraus mentioned, runtime.GetHeap() can break. I was able to resolve this issue by creating my runtime as follows:

DataTarget target = DataTarget.AttachProcess(pid, timeout, mode);
ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
ClrHeap heap = runtime.GetHeap();

All the nonsense with TryGetDacLocation() is now unnecessary.

Adam
  • 61
  • 1
  • 1