summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2014-10-14 19:14:33 +0000
committerCorinna Vinschen <corinna@vinschen.de>2014-10-14 19:14:33 +0000
commit1dd75c50d5727dcd9330377053dfe673d617fead (patch)
treec6f6d2d649730df4393715f7c5cec0761e40008e
parent2599a694a6c3b74a9c6424e933d964a4fee06309 (diff)
downloadcygnal-1dd75c50d5727dcd9330377053dfe673d617fead.tar.gz
cygnal-1dd75c50d5727dcd9330377053dfe673d617fead.tar.bz2
cygnal-1dd75c50d5727dcd9330377053dfe673d617fead.zip
* 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.
-rw-r--r--winsup/cygwin/ChangeLog12
-rw-r--r--winsup/cygwin/cygheap.cc10
-rw-r--r--winsup/cygwin/cygheap.h15
-rw-r--r--winsup/cygwin/dlfcn.cc33
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,5 +1,17 @@
2014-10-14 Corinna Vinschen <corinna@vinschen.de>
+ * 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 <corinna@vinschen.de>
+
* fhandler_socket.cc (fhandler_socket::connect): Init connect_state to
connect_pending only on unconnected socket. Set connect_state to
connected on WSAEISCONN error. Set connect_state to connect_failed
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 <psapi.h>
#include <stdlib.h>
#include <ctype.h>
+#include <wctype.h>
#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);