...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.

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:
Signed-off-by: Takashi Yano <[email protected]>
---
 winsup/cygwin/local_includes/cygheap.h |  2 ++
 winsup/cygwin/mm/cygheap.cc            | 22 +++++++++++++++++-----
 winsup/cygwin/spawn.cc                 |  4 +++-
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/local_includes/cygheap.h 
b/winsup/cygwin/local_includes/cygheap.h
index fed87ec2b..aa928bc55 100644
--- a/winsup/cygwin/local_includes/cygheap.h
+++ b/winsup/cygwin/local_includes/cygheap.h
@@ -541,6 +541,8 @@ struct init_cygheap: public mini_cygheap
   threadlist_t *find_tls (int, bool&);
   sigset_t compute_sigblkmask ();
   void unlock_tls (threadlist_t *t) { if (t) ReleaseMutex (t->mutex); }
+  void lock ();
+  void unlock ();
 };
 
 
diff --git a/winsup/cygwin/mm/cygheap.cc b/winsup/cygwin/mm/cygheap.cc
index 338886468..2ed21e6ce 100644
--- a/winsup/cygwin/mm/cygheap.cc
+++ b/winsup/cygwin/mm/cygheap.cc
@@ -262,6 +262,18 @@ init_cygheap::init_installation_root ()
     }
 }
 
+void
+init_cygheap::lock ()
+{
+  AcquireSRWLockExclusive (&cygheap_protect);
+}
+
+void
+init_cygheap::unlock ()
+{
+  ReleaseSRWLockExclusive (&cygheap_protect);
+}
+
 /* Initialize bucket_val.  The value is the max size of a block
    fitting into the bucket.  The values are powers of two and their
    medians: 32, 48, 64, 96, ...
@@ -367,7 +379,7 @@ _cmalloc (unsigned size)
   if (b >= NBUCKETS)
     return NULL;
 
-  AcquireSRWLockExclusive (&cygheap_protect);
+  cygheap->lock ();
   if (cygheap->buckets[b])
     {
       rvc = (_cmalloc_entry *) cygheap->buckets[b];
@@ -379,7 +391,7 @@ _cmalloc (unsigned size)
       rvc = (_cmalloc_entry *) _csbrk (bucket_val[b] + sizeof 
(_cmalloc_entry));
       if (!rvc)
        {
-         ReleaseSRWLockExclusive (&cygheap_protect);
+         cygheap->unlock ();
          return NULL;
        }
 
@@ -387,19 +399,19 @@ _cmalloc (unsigned size)
       rvc->prev = cygheap->chain;
       cygheap->chain = rvc;
     }
-  ReleaseSRWLockExclusive (&cygheap_protect);
+  cygheap->unlock ();
   return rvc->data;
 }
 
 static void
 _cfree (void *ptr)
 {
-  AcquireSRWLockExclusive (&cygheap_protect);
+  cygheap->lock ();
   _cmalloc_entry *rvc = to_cmalloc (ptr);
   unsigned b = rvc->b;
   rvc->ptr = cygheap->buckets[b];
   cygheap->buckets[b] = (char *) rvc;
-  ReleaseSRWLockExclusive (&cygheap_protect);
+  cygheap->unlock ();
 }
 
 static void *
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index cb58b6eed..fd623f4c5 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;
 
+      cygheap->lock ();
+      refresh_cygheap ();
       wchar_t wcmd[(size_t) cmd];
       if (!::cygheap->user.issetuid ()
          || (::cygheap->user.saved_uid == ::cygheap->user.real_uid
@@ -844,6 +845,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;
+      cygheap->unlock ();
 
       switch (mode)
        {
-- 
2.45.1

Reply via email to