Browse Source

Bug 2005: Hang when running under Task Scheduler or a similar service with session logging enabled

https://winscp.net/tracker/2005
(cherry picked from commit 2b0da7b9a7e50f3b9f8ea3bf9be971d2436b1d42)

# Conflicts:
#	source/core/Common.cpp

Source commit: 281e508faaf32d043f1c03c07756e977dec2b1c1
Martin Prikryl 4 years ago
parent
commit
17b6ed1a68
1 changed files with 45 additions and 30 deletions
  1. 45 30
      source/core/Common.cpp

+ 45 - 30
source/core/Common.cpp

@@ -4134,34 +4134,19 @@ DWORD __fastcall GetParentProcessId(HANDLE Snapshot, DWORD ProcessId)
 static UnicodeString GetProcessName(DWORD ProcessId)
 {
   UnicodeString Result;
-  if (ProcessId == 0)
-  {
-    Result = L"err-notfound";
-  }
-  else
-  {
-    HANDLE Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessId);
-    if (!Process)
+  HANDLE Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessId);
+   // is common, when the parent process is installer, so we ignore it
+  if (Process)
+  {
+    Result.SetLength(MAX_PATH);
+    DWORD Len = GetModuleFileNameEx(Process, NULL, Result.c_str(), Result.Length());
+    Result.SetLength(Len);
+    // is common too, for some reason
+    if (!Result.IsEmpty())
     {
-      // is common, when the parent process is installer, so we ignore it
-      Result = UnicodeString();
-    }
-    else
-    {
-      Result.SetLength(MAX_PATH);
-      DWORD Len = GetModuleFileNameEx(Process, NULL, Result.c_str(), Result.Length());
-      if (Len == 0)
-      {
-        // is common too, for some reason
-        Result = UnicodeString();
-      }
-      else
-      {
-        Result.SetLength(Len);
-        Result = ExtractProgramName(FormatCommand(Result, UnicodeString()));
-      }
-      CloseHandle(Process);
+      Result = ExtractProgramName(FormatCommand(Result, UnicodeString()));
     }
+    CloseHandle(Process);
   }
   return Result;
 }
@@ -4184,21 +4169,51 @@ UnicodeString __fastcall GetAncestorProcessName(int Levels)
 
       DWORD ProcessId = GetCurrentProcessId();
 
+      typedef std::vector<DWORD> TProcesses;
+      TProcesses Processes;
       // Either more to go (>0) or collecting all levels (-1 from GetAncestorProcessNames)
       while ((Levels != 0) &&
+             (Levels > -20) && // prevent infinite loops
              (ProcessId != 0))
       {
+        const UnicodeString Sep(L", ");
         ProcessId = GetParentProcessId(Snapshot, ProcessId);
-        if ((Levels < 0) && (ProcessId != 0))
+        // When ancestor process is terminated and another process reuses its ID, we may get a cycle.
+        TProcesses::const_iterator I = std::find(Processes.begin(), Processes.end(), ProcessId);
+        if (I != Processes.end())
         {
-          AddToList(Result, GetProcessName(ProcessId), L", ");
+          int Index = I - Processes.begin();
+          AddToList(Result, FORMAT(L"cycle-%d", (Index)), Sep);
+          ProcessId = 0;
+        }
+        else
+        {
+          Processes.push_back(ProcessId);
+
+          if ((Levels < 0) && (ProcessId != 0))
+          {
+            UnicodeString Name = GetProcessName(ProcessId);
+            if (Name.IsEmpty())
+            {
+              Name = L"...";
+              ProcessId = 0;
+            }
+            AddToList(Result, Name, Sep);
+          }
+          Levels--;
         }
-        Levels--;
       }
 
       if (Levels >= 0)
       {
-        Result = GetProcessName(ProcessId);
+        if (ProcessId == 0)
+        {
+          Result = L"err-notfound";
+        }
+        else
+        {
+          Result = GetProcessName(ProcessId);
+        }
       }
       else if (Result.IsEmpty())
       {