summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2010-12-09 16:50:36 +0000
committerCorinna Vinschen <corinna@vinschen.de>2010-12-09 16:50:36 +0000
commit0dcfb061cf1e2ed2acfb0b605ac3933ff726e17f (patch)
treeaea009c4ffdd2338a1942fc5cf6dccb2f6f6bec6
parent23dbdc2aaa4b620a40596a50e24f2ea0a8ecb78f (diff)
downloadcygnal-0dcfb061cf1e2ed2acfb0b605ac3933ff726e17f.tar.gz
cygnal-0dcfb061cf1e2ed2acfb0b605ac3933ff726e17f.tar.bz2
cygnal-0dcfb061cf1e2ed2acfb0b605ac3933ff726e17f.zip
* autoload.cc (RETRY_COUNT): New define.
(std_dll_init): Restructure loop to retry loading a DLL only if specific errors occur. If these errors persist, try to load DLL with name only.
-rw-r--r--winsup/cygwin/ChangeLog7
-rw-r--r--winsup/cygwin/autoload.cc46
2 files changed, 39 insertions, 14 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index bfaff82a0..85d3bf0ab 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,10 @@
+2010-12-09 Corinna Vinschen <corinna@vinschen.de>
+
+ * autoload.cc (RETRY_COUNT): New define.
+ (std_dll_init): Restructure loop to retry loading a DLL only if
+ specific errors occur. If these errors persist, try to load DLL
+ with name only.
+
2010-12-08 Corinna Vinschen <corinna@vinschen.de>
* include/strings.h: Remove in favor of equivalent newlib file.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 1c6429204..2e495ad6a 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -204,6 +204,8 @@ union retchain
long long ll;
};
+#define RETRY_COUNT 10
+
/* The standard DLL initialization routine. */
__attribute__ ((used, noinline)) static long long
std_dll_init ()
@@ -221,27 +223,43 @@ std_dll_init ()
while (InterlockedIncrement (&dll->here));
else if (!dll->handle)
{
- HANDLE h;
fenv_t fpuenv;
fegetenv (&fpuenv);
WCHAR dll_path[MAX_PATH];
+ DWORD err = ERROR_SUCCESS;
/* http://www.microsoft.com/technet/security/advisory/2269637.mspx */
wcpcpy (wcpcpy (dll_path, windows_system_directory), dll->name);
- dll->handle = NULL;
/* MSDN seems to imply that LoadLibrary can fail mysteriously, so,
since there have been reports of this in the mailing list, retry
- several times before giving up. */
- for (int i = 1; !dll->handle && i <= 5; i++)
- if ((h = LoadLibraryW (dll_path)) != NULL)
- dll->handle = h;
- /* FIXME: This isn't quite right. Probably should check for specific
- error codes. */
- else if ((func->decoration & 1))
- dll->handle = INVALID_HANDLE_VALUE;
- else if (i < 5)
- yield ();
- else
- api_fatal ("could not load %W, %E", dll_path);
+ several times before giving up. */
+ for (int i = 1; i <= RETRY_COUNT; i++)
+ {
+ /* If loading the library succeeds, just leave the loop. */
+ if ((dll->handle = LoadLibraryW (dll_path)) != NULL)
+ break;
+ /* Otherwise check error code returned by LoadLibrary. If the
+ error code is neither NOACCESS nor DLL_INIT_FAILED, break out
+ of the loop. */
+ err = GetLastError ();
+ if (err != ERROR_NOACCESS && err != ERROR_DLL_INIT_FAILED)
+ break;
+ if (i < RETRY_COUNT)
+ yield ();
+ }
+ if (!dll->handle)
+ {
+ /* If LoadLibrary with full path returns one of the weird errors
+ reported on the Cygwin mailing list, retry with only the DLL
+ name. Checking the error codes allows to restrict loading
+ with just the DLL name to this specific problem. */
+ if ((err == ERROR_NOACCESS || err == ERROR_DLL_INIT_FAILED)
+ && (dll->handle = LoadLibraryW (dll->name)) != NULL)
+ ;
+ else if ((func->decoration & 1))
+ dll->handle = INVALID_HANDLE_VALUE;
+ else
+ api_fatal ("could not load %W, %E", dll_path);
+ }
fesetenv (&fpuenv);
}