>From 8607cf5dad47de078ef7a74676386e9eb981c2a8 Mon Sep 17 00:00:00 2001
From: David Allsopp <david.allsopp@metastack.com>
Date: Mon, 27 Feb 2017 17:06:34 +0000
Subject: [PATCH] Preserve order of dlopen'd modules in dll_list::topsort

Signed-off-by: David Allsopp <david.allsopp@metastack.com>
---
 winsup/cygwin/dll_init.cc   | 58 ++++++++++++++++++++++++++++++++++++++++-----
 winsup/cygwin/release/2.7.1 |  2 ++
 2 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index 0fe5714..e3a710a 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -271,9 +271,16 @@ void dll_list::populate_deps (dll* d)
   PIMAGE_DATA_DIRECTORY dd = pef->idata_dir (IMAGE_DIRECTORY_ENTRY_IMPORT);
   /* Annoyance: calling crealloc with a NULL pointer will use the
      wrong heap and crash, so we have to replicate some code */
-  long maxdeps = 4;
-  d->deps = (dll**) cmalloc (HEAP_2_DLL, maxdeps*sizeof (dll*));
-  d->ndeps = 0;
+  long maxdeps;
+  if (!d->ndeps)
+    {
+      maxdeps = 4;
+      d->deps = (dll**) cmalloc (HEAP_2_DLL, maxdeps*sizeof (dll*));
+    }
+  else
+    {
+      maxdeps = d->ndeps;
+    }
   for (PIMAGE_IMPORT_DESCRIPTOR id=
 	(PIMAGE_IMPORT_DESCRIPTOR) pef->rva (dd->VirtualAddress);
       dd->Size && id->Name;
@@ -306,9 +313,48 @@ dll_list::topsort ()
 
   /* make sure we have all the deps available */
   dll* d = &start;
-  while ((d = d->next))
-    if (!d->ndeps)
-      populate_deps (d);
+  if (loaded_dlls > 0)
+    {
+      /* Ensure that all dlopen'd DLLs depend on previously dlopen'd DLLs. This
+         prevents topsort from reversing the order of dlopen'd DLLs on calls to
+         fork. */
+      long maxdeps = 4;
+      long dlopen_ndeps = 0;
+      dll** dlopen_deps = (dll**) cmalloc (HEAP_2_DLL, maxdeps*sizeof (dll*));
+      while ((d = d->next))
+        {
+          if (!d->ndeps)
+            {
+              if (d->type == DLL_LOAD)
+                {
+                  /* Initialise d->deps with all previously dlopen'd DLLs. */
+                  if (dlopen_ndeps)
+                    {
+                      d->ndeps = dlopen_ndeps;
+                      d->deps = (dll**) cmalloc (HEAP_2_DLL,
+                                                 dlopen_ndeps*sizeof (dll*));
+                      memcpy (d->deps, dlopen_deps, dlopen_ndeps*sizeof (dll*));
+                    }
+                  /* Add this DLL to the list of previously dlopen'd DLLs. */
+                  if (dlopen_ndeps >= maxdeps)
+                    {
+                      maxdeps = 2*(1+maxdeps);
+                      dlopen_deps = (dll**) crealloc(dlopen_deps,
+                                                     maxdeps*sizeof (dll*));
+                    }
+                  dlopen_deps[dlopen_ndeps++] = d;
+                }
+              populate_deps (d);
+            }
+        }
+      cfree(dlopen_deps);
+    }
+  else
+    {
+      while ((d = d->next))
+        if (!d->ndeps)
+          populate_deps (d);
+    }
 
   /* unlink head and tail pointers so the sort can rebuild the list */
   d = start.next;
diff --git a/winsup/cygwin/release/2.7.1 b/winsup/cygwin/release/2.7.1
index 54e1100..411a0ae 100644
--- a/winsup/cygwin/release/2.7.1
+++ b/winsup/cygwin/release/2.7.1
@@ -8,6 +8,8 @@ What changed:
 - cygcheck and strace now always generate output with Unix LF line endings,
   rather than with DOS/Windows CR LF line endings.
 
+- fork now preserves the load order of unrelated dlopen'd modules.
+
 
 Bug Fixes
 ---------
-- 
2.10.2.windows.1

