...completion in child process because the cygheap should not be
changed to avoid mismatch between child_info::cygheap_max and
::cygheap_max. Otherwise, child_copy() might copy cygheap being
modified by other process. However, do not lock cygheap if the
child process is non-cygwin process, because child_copy() will
not be called in it. Not only it is unnecessary, it can also fall
into deadlock in close_all_files() while cygheap is already locked.

Fixes: 977ad5434cc0 ("* spawn.cc (spawn_guts): Call refresh_cygheap before 
creating a new process to ensure that cygheap_max is up-to-date.")
Reviewed-by: Corinna Vinschen <cori...@vinschen.de>
Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp>
---
 winsup/cygwin/local_includes/child_info.h | 10 ++++++++++
 winsup/cygwin/spawn.cc                    |  7 ++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/local_includes/child_info.h 
b/winsup/cygwin/local_includes/child_info.h
index 2da62ffaa..460a83684 100644
--- a/winsup/cygwin/local_includes/child_info.h
+++ b/winsup/cygwin/local_includes/child_info.h
@@ -191,6 +191,16 @@ public:
   operator HANDLE& () {return hExeced;}
   int worker (const char *, const char *const *, const char *const [],
                     int, int = -1, int = -1);
+  inline void spawn_cygheap_lock ()
+  {
+    if (iscygwin ())
+      cygheap->lock ();
+  }
+  inline void spawn_cygheap_unlock ()
+  {
+    if (iscygwin ())
+      cygheap->unlock ();
+  }
 };
 
 extern child_info_spawn ch_spawn;
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index cb58b6eed..8ca19868a 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -542,7 +542,6 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
        ::cygheap->ctty ? ::cygheap->ctty->tc_getpgid () : 0;
       if (!iscygwin () && ctty_pgid && ctty_pgid != myself->pgid)
        c_flags |= CREATE_NEW_PROCESS_GROUP;
-      refresh_cygheap ();
 
       if (mode == _P_DETACH)
        /* all set */;
@@ -611,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
 
       cygpid = (mode != _P_OVERLAY) ? create_cygwin_pid () : myself->pid;
 
+      spawn_cygheap_lock ();
+      refresh_cygheap ();
       wchar_t wcmd[(size_t) cmd];
       if (!::cygheap->user.issetuid ()
          || (::cygheap->user.saved_uid == ::cygheap->user.real_uid
@@ -728,6 +729,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
            ::cygheap->user.reimpersonate ();
 
          res = -1;
+         spawn_cygheap_unlock ();
          __leave;
        }
 
@@ -781,6 +783,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
              if (get_errno () != ENOMEM)
                set_errno (EAGAIN);
              res = -1;
+             spawn_cygheap_unlock ();
              __leave;
            }
          child->dwProcessId = pi.dwProcessId;
@@ -816,6 +819,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
              CloseHandle (pi.hProcess);
              ForceCloseHandle (pi.hThread);
              res = -1;
+             spawn_cygheap_unlock ();
              __leave;
            }
        }
@@ -844,6 +848,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
        /* Just mark a non-cygwin process as 'synced'.  We will still eventually
           wait for it to exit in maybe_set_exit_code_from_windows(). */
        synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : 
true;
+      spawn_cygheap_unlock ();
 
       switch (mode)
        {
-- 
2.45.1

Reply via email to