summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/dll_init.cc
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2012-03-04 16:47:45 +0000
committerCorinna Vinschen <corinna@vinschen.de>2012-03-04 16:47:45 +0000
commitf5b0d9d414b7be8e93363fb7a2d46425710585f7 (patch)
treee968510cc300d7e40564ac8941c0d58353058e96 /winsup/cygwin/dll_init.cc
parent50124fc05680a1f01a52a28bd89abb86ccc8eae7 (diff)
downloadcygnal-f5b0d9d414b7be8e93363fb7a2d46425710585f7.tar.gz
cygnal-f5b0d9d414b7be8e93363fb7a2d46425710585f7.tar.bz2
cygnal-f5b0d9d414b7be8e93363fb7a2d46425710585f7.zip
* 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.
Diffstat (limited to 'winsup/cygwin/dll_init.cc')
-rw-r--r--winsup/cygwin/dll_init.cc34
1 files changed, 30 insertions, 4 deletions
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index 74c51ed5f..170cf84e0 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -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,