]> sourceware.org Git - newlib-cygwin.git/commitdiff
* dll_init.cc (dll_list::alloc): Compare linked DLLs by basename only.
authorCorinna Vinschen <corinna@vinschen.de>
Sun, 4 Mar 2012 16:47:45 +0000 (16:47 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Sun, 4 Mar 2012 16:47:45 +0000 (16:47 +0000)
Explain why.  Add code to check if a DLL with the same basename but
different path is the same DLL.  Bail out if not.
(in_load_after_fork): New static NO_COPY bool to allow to differ
between linked and loaded DLL at fork.
(dll_list::load_after_fork): Set in_load_after_fork accordingly.
(dll_dllcrt0_1): Don't treat DLL as linked if in_load_after_fork is set.
Drop test for in_forkee.

winsup/cygwin/ChangeLog
winsup/cygwin/dll_init.cc

index 13709bcde6b192e2cc8f29642ae4abd900c702cf..af6b079e60d8969120fd80687407d0db5e1c1715 100644 (file)
@@ -1,3 +1,14 @@
+2012-03-04  Corinna Vinschen  <corinna@vinschen.de>
+
+       * dll_init.cc (dll_list::alloc): Compare linked DLLs by basename only.
+       Explain why.  Add code to check if a DLL with the same basename but
+       different path is the same DLL.  Bail out if not.
+       (in_load_after_fork): New static NO_COPY bool to allow to differ
+       between linked and loaded DLL at fork.
+       (dll_list::load_after_fork): Set in_load_after_fork accordingly.
+       (dll_dllcrt0_1): Don't treat DLL as linked if in_load_after_fork is set.
+       Drop test for in_forkee.
+
 2012-03-04  Corinna Vinschen  <corinna@vinschen.de>
 
        * dll_init.cc: Revert pathname changes from 2012-02-08.
index 74c51ed5fe926b9cee59f86048517c4703dd2cd5..170cf84e0edbd33ebb33f08ab9655dab738b9348 100644 (file)
@@ -167,10 +167,13 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
   if (!wcsncmp (name, L"\\\\?\\", 4))
     name += 4;
   DWORD namelen = wcslen (name);
+  PWCHAR modname = wcsrchr (name, L'\\') + 1;
 
   guard (true);
-  /* Already loaded? */
-  dll *d = dlls[name];
+  /* Already loaded?  For linked DLLs, only compare the basenames.  Linked
+     DLLs are loaded using just the basename and the default DLL search path.
+     The Windows loader picks up the first one it finds.  */
+  dll *d = (type == DLL_LINK) ? dlls.find_by_modname (modname) : dlls[name];
   if (d)
     {
       if (!in_forkee)
@@ -178,6 +181,21 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
       else if (d->handle != h)
        fabort ("%W: Loaded to different address: parent(%p) != child(%p)",
                name, d->handle, h);
+      /* If this DLL has been linked against, and the full path differs, try
+        to sanity check if this is the same DLL, just in another path. */
+      else if (type == DLL_LINK && wcscasecmp (name, d->name)
+              && (d->p.data_start != p->data_start
+                  || d->p.data_start != p->data_start
+                  || d->p.bss_start != p->bss_start
+                  || d->p.bss_end != p->bss_end
+                  || d->p.ctors != p->ctors
+                  || d->p.dtors != p->dtors))
+       fabort ("\nLoaded different DLL with same basename in forked child,\n"
+               "parent loaded: %W\n"
+               " child loaded: %W\n"
+               "The DLLs differ, so it's not safe to run the forked child.\n"
+               "Make sure to remove the offending DLL before trying again.",
+               d->name, name);
       d->p = p;
     }
   else
@@ -189,7 +207,7 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
         supplied info about this DLL. */
       d->count = 1;
       wcscpy (d->name, name);
-      d->modname = wcsrchr (d->name, L'\\') + 1;
+      d->modname = d->name + (modname - name);
       d->handle = h;
       d->has_dtors = true;
       d->p = p;
@@ -446,6 +464,12 @@ dll_list::reserve_space ()
              d->modname, d->handle);
 }
 
+/* We need the in_load_after_fork flag so dll_dllcrt0_1 can decide at fork
+   time if this is a linked DLL or a dynamically loaded DLL.  In either case,
+   both, cygwin_finished_initializing and in_forkee are true, so they are not
+   sufficient to discern the situation. */
+static bool NO_COPY in_load_after_fork;
+
 /* Reload DLLs after a fork.  Iterates over the list of dynamically loaded
    DLLs and attempts to load them in the same place as they were loaded in the
    parent. */
@@ -455,7 +479,9 @@ dll_list::load_after_fork (HANDLE parent)
   // moved to frok::child for performance reasons:
   // dll_list::reserve_space();
 
+  in_load_after_fork = true;
   load_after_fork_impl (parent, dlls.istart (DLL_LOAD), 0);
+  in_load_after_fork = false;
 }
 
 static int const DLL_RETRY_MAX = 6;
@@ -582,7 +608,7 @@ dll_dllcrt0_1 (VOID *x)
       _pei386_runtime_relocator (p);
     }
 
-  bool linked = !in_forkee && !cygwin_finished_initializing;
+  bool linked = !cygwin_finished_initializing && !in_load_after_fork;
 
   /* Broken DLLs built against Cygwin versions 1.7.0-49 up to 1.7.0-57
      override the cxx_malloc pointer in their DLL initialization code,
This page took 0.037582 seconds and 5 git commands to generate.