summaryrefslogtreecommitdiff
path: root/dln.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-05-16 06:09:40 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-05-16 06:09:40 +0000
commit6c05f91b3b12c9a52cf36fae2ad6fb7eaf9d53e3 (patch)
tree75979570b421b1819e9d996895f67d508a4c2db6 /dln.c
parentfdac9a36c26b7a4240e2552e67bae450f4f36eab (diff)
downloadruby-6c05f91b3b12c9a52cf36fae2ad6fb7eaf9d53e3.tar.gz
* dln.c (rb_w32_check_imported): check if extension library to be
loaded imports from different ruby dll. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27816 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'dln.c')
-rw-r--r--dln.c80
1 files changed, 58 insertions, 22 deletions
diff --git a/dln.c b/dln.c
index 04d1fa212c..6dceeb3878 100644
--- a/dln.c
+++ b/dln.c
@@ -1116,9 +1116,29 @@ dln_sym(const char *name)
#if defined _WIN32 && !defined __CYGWIN__
#include <windows.h>
+#include <imagehlp.h>
#endif
-#if ! defined _AIX
+#if defined _WIN32 && !defined __CYGWIN__
+static const char *
+dln_strerror(char *message, size_t size)
+{
+ int error = GetLastError();
+ char *p = message;
+ size_t len = snprintf(message, size, "%d: ", error);
+
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ message + len, size - len, NULL);
+ for (p = message + len; *p; p++) {
+ if (*p == '\n' || *p == '\r')
+ *p = ' ';
+ }
+ return message;
+}
+#define dln_strerror() dln_strerror(message, sizeof message)
+#elif ! defined _AIX
static const char *
dln_strerror(void)
{
@@ -1146,27 +1166,6 @@ dln_strerror(void)
#ifdef USE_DLN_DLOPEN
return (char*)dlerror();
#endif
-
-#if defined _WIN32 && !defined __CYGWIN__
- static char message[1024];
- int error = GetLastError();
- char *p = message;
- p += sprintf(message, "%d: ", error);
- FormatMessage(
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- error,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- p,
- sizeof message - strlen(message),
- NULL);
-
- for (p = message; *p; p++) {
- if (*p == '\n' || *p == '\r')
- *p = ' ';
- }
- return message;
-#endif
}
#endif
@@ -1196,6 +1195,36 @@ aix_loaderror(const char *pathname)
}
#endif
+#if defined _WIN32 && defined RUBY_EXPORT
+HANDLE rb_libruby_handle(void);
+
+static int
+rb_w32_check_imported(HMODULE ext, HMODULE mine)
+{
+ ULONG size;
+ const IMAGE_IMPORT_DESCRIPTOR *desc;
+
+ desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
+ if (!desc) return 0;
+ while (desc->Name) {
+ PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics);
+ PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk);
+ while (piat->u1.Function) {
+ PIMAGE_IMPORT_BY_NAME pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + pint->u1.AddressOfData);
+ static const char prefix[] = "rb_";
+ if (strncmp(pii->Name, prefix, sizeof(prefix) - 1) == 0) {
+ FARPROC addr = GetProcAddress(mine, pii->Name);
+ if (addr) return (FARPROC)piat->u1.Function == addr;
+ }
+ piat++;
+ pint++;
+ }
+ desc++;
+ }
+ return 1;
+}
+#endif
+
#if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
#define translit_separator(src) do { \
char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
@@ -1219,6 +1248,7 @@ dln_load(const char *file)
#if defined _WIN32 && !defined __CYGWIN__
HINSTANCE handle;
char winfile[MAXPATHLEN];
+ char message[1024];
void (*init_fct)();
char *buf;
@@ -1235,6 +1265,12 @@ dln_load(const char *file)
goto failed;
}
+ if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
+ FreeLibrary(handle);
+ error = "incompatible library version";
+ goto failed;
+ }
+
if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
}