+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.
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)
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
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;
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. */
// 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;
_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,