Fix dotnet-dump collect on half exited process (#2959)
authorMike McLaughlin <mikem@microsoft.com>
Fri, 25 Mar 2022 03:21:10 +0000 (20:21 -0700)
committerGitHub <noreply@github.com>
Fri, 25 Mar 2022 03:21:10 +0000 (20:21 -0700)
Fix dotnet-dump collect on half exited process

Issue: https://github.com/dotnet/diagnostics/issues/2950

Changed to pinvoke directly to OpenProcess to get the process handle for MiniDumpWriteDump.

src/Tools/dotnet-dump/Dumper.Windows.cs
src/Tools/dotnet-dump/Dumper.cs

index 3f8b5d19a60949c8df0327470d997f0c5674cc38..12d4d5cc1945a2f631684e9d03530fc621b55ef2 100644 (file)
@@ -7,7 +7,6 @@ using System;
 using System.Diagnostics;
 using System.IO;
 using System.Runtime.InteropServices;
-using System.Threading.Tasks;
 
 namespace Microsoft.Diagnostics.Tools.Dump
 {
@@ -15,8 +14,16 @@ namespace Microsoft.Diagnostics.Tools.Dump
     {
         private static class Windows
         {
-            internal static void CollectDump(Process process, string outputFile, DumpTypeOption type)
+            internal static void CollectDump(int processId, string outputFile, DumpTypeOption type)
             {
+                // The managed Process (via Process.GetProcessById) type can not be used to get the handle for a process that is in the middle of exiting such
+                // that it has set an exit code, but not actually exited. This is because for compat reasons the Process class will throw in these circumstances.
+                using SafeProcessHandle processHandle = NativeMethods.OpenProcess(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.PROCESS_VM_READ, false, processId);
+                if (processHandle.IsInvalid)
+                {
+                    throw new ArgumentException($"Invalid process id {processId} error: {Marshal.GetLastWin32Error()}");
+                }
+
                 // Open the file for writing
                 using (var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                 {
@@ -63,7 +70,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
                     for (int i = 0; i < 5; i++)
                     {
                         // Dump the process!
-                        if (NativeMethods.MiniDumpWriteDump(process.Handle, (uint)process.Id, stream.SafeFileHandle, dumpType, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
+                        if (NativeMethods.MiniDumpWriteDump(processHandle.DangerousGetHandle(), (uint)processId, stream.SafeFileHandle, dumpType, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
                         {
                             break;
                         }
@@ -83,8 +90,14 @@ namespace Microsoft.Diagnostics.Tools.Dump
             {
                 public const int ERROR_PARTIAL_COPY = unchecked((int)0x8007012b);
 
+                public const int PROCESS_VM_READ = 0x0010;
+                public const int PROCESS_QUERY_INFORMATION = 0x0400;
+
+                [DllImport("kernel32.dll", SetLastError = true)]
+                public extern static SafeProcessHandle OpenProcess(int access, [MarshalAs(UnmanagedType.Bool)] bool inherit, int processId);
+
                 [DllImport("Dbghelp.dll", SetLastError = true)]
-                public static extern bool MiniDumpWriteDump(IntPtr hProcess, uint ProcessId, SafeFileHandle hFile, MINIDUMP_TYPE DumpType, IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallbackParam);
+                public extern static bool MiniDumpWriteDump(IntPtr hProcess, uint ProcessId, SafeFileHandle hFile, MINIDUMP_TYPE DumpType, IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallbackParam);
 
                 [StructLayout(LayoutKind.Sequential, Pack = 4)]
                 public struct MINIDUMP_EXCEPTION_INFORMATION
index ce8ec9d5c9161056f0c01431c27d5b9eade8c268..9e406ea28ae6c6b1fd827617697071c90ee87a25 100644 (file)
@@ -92,10 +92,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
                         return 0;
                     }
 
-                    // Get the process
-                    Process process = Process.GetProcessById(processId);
-
-                    Windows.CollectDump(process, output, type);
+                    Windows.CollectDump(processId, output, type);
                 }
                 else
                 {
@@ -133,6 +130,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
             }
             catch (Exception ex) when 
                 (ex is FileNotFoundException || 
+                 ex is ArgumentException || 
                  ex is DirectoryNotFoundException || 
                  ex is UnauthorizedAccessException || 
                  ex is PlatformNotSupportedException ||