From 1dd75c50d5727dcd9330377053dfe673d617fead Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 14 Oct 2014 19:14:33 +0000 Subject: * cygheap.cc (init_cygheap::init_installation_root): Install Cygwin's installation dir as DLL search path, instead of ".". * cygheap.h (class cwdstuff): Add parameter names in function declarations for readability. (cwdstuff::get): Ad inline implementation fetching the CWD as wide char string. * dlfcn.cc (dlopen): Add searching for dependent DLLs in DLL installation dir or CWD, if all else failed. Add comment to explain scenarios this is accommodating. --- winsup/cygwin/ChangeLog | 12 ++++++++++++ winsup/cygwin/cygheap.cc | 10 +++++++++- winsup/cygwin/cygheap.h | 15 ++++++++++++--- winsup/cygwin/dlfcn.cc | 33 ++++++++++++++++++++++++++++++++- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5650c6342..3d5a5fe86 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,15 @@ +2014-10-14 Corinna Vinschen + + * cygheap.cc (init_cygheap::init_installation_root): Install Cygwin's + installation dir as DLL search path, instead of ".". + * cygheap.h (class cwdstuff): Add parameter names in function + declarations for readability. + (cwdstuff::get): Ad inline implementation fetching the CWD as wide char + string. + * dlfcn.cc (dlopen): Add searching for dependent DLLs in DLL + installation dir or CWD, if all else failed. + Add comment to explain scenarios this is accommodating. + 2014-10-14 Corinna Vinschen * fhandler_socket.cc (fhandler_socket::connect): Init connect_state to diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index 067aa68dd..7e261ed48 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -170,7 +170,6 @@ init_cygheap::init_installation_root () } } installation_root[1] = L'?'; - RtlInitEmptyUnicodeString (&installation_key, installation_key_buf, sizeof installation_key_buf); RtlInt64ToHexUnicodeString (hash_path_name (0, installation_root), @@ -185,6 +184,15 @@ init_cygheap::init_installation_root () if (!w) api_fatal ("Can't initialize Cygwin installation root dir.\n" "Invalid DLL path"); + + /* Remove "." from DLL search path and install our /bin dir instead. + Note that this change is propagated to child processes so we don't + have to call SetDllDirectory in each process. */ + installation_root[1] = L'\\'; + if (!SetDllDirectoryW (installation_root)) + debug_printf ("Couldn't set %W as DLL directory, %E", installation_root); + installation_root[1] = L'?'; + /* If w < p, the Cygwin DLL resides in the root dir of a drive or network path. In that case, if we strip off yet another backslash, the path becomes invalid. We avoid that here so that the DLL also works in this diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index b08569d13..c2f60e94d 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -308,14 +308,23 @@ private: available in shared memory avoids to test for the version every time around. Default to new version. */ fcwd_version_t fast_cwd_version; - void override_win32_cwd (bool, ULONG); + void override_win32_cwd (bool init, ULONG old_dismount_count); public: UNICODE_STRING win32; static muto cwd_lock; const char *get_posix () const { return posix; }; - void reset_posix (wchar_t *); - char *get (char *, int = 1, int = 0, unsigned = NT_MAX_PATH); + void reset_posix (wchar_t *w_cwd); + char *get (char *buf, int need_posix = 1, int with_chroot = 0, + unsigned ulen = NT_MAX_PATH); + PWCHAR get (PWCHAR buf, unsigned buflen = NT_MAX_PATH) + { + cwd_lock.acquire (); + buf[0] = L'\0'; + wcsncat (buf, win32.Buffer, buflen - 1); + cwd_lock.release (); + return buf; + } HANDLE get_handle () { return dir; } DWORD get_drive (char * dst) { diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index 46d654f0b..2c74a1497 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -13,7 +13,11 @@ details. */ #include #include #include +#include #include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" #include "perprocess.h" #include "dlfcn.h" #include "cygtls.h" @@ -156,7 +160,34 @@ dlopen (const char *name, int flags) if (flags & RTLD_NOLOAD) GetModuleHandleExW (0, path, (HMODULE *) &ret); else - ret = (void *) LoadLibraryW (path); + { + ret = (void *) LoadLibraryW (path); + if (!ret && GetLastError () == ERROR_MOD_NOT_FOUND) + { + /* This may indicate that a dependent DLL could not be loaded. + Typically this occurs because we removed the CWD from the + DLL search path via SetDllDirectory + (see init_cygheap::init_installation_root), and the load + mechanism expects that dlopening a DLL from the CWD allows + to load dependent DLLs from the same dir. + + To continue supporting this scenario, call LoadLibraryEx + with the LOAD_WITH_ALTERED_SEARCH_PATH flag. This flag + replaces the application path with the DLL path in the DLL + search order. This functionality needs the full path to + the loaded DLL. */ + if (!strchr (name, '/')) + { + wchar_t *path_full = tp.w_get (); + cygheap->cwd.get (path_full); + wcscat (path_full, L"\\"); + wcscat (path_full, path); + path = path_full; + } + ret = (void *) LoadLibraryExW (path, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + } + } if (ret && (flags & RTLD_NODELETE)) GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_PIN, path, (HMODULE *) &ret); -- cgit v1.2.3