summaryrefslogtreecommitdiff
path: root/dln.c
diff options
context:
space:
mode:
Diffstat (limited to 'dln.c')
-rw-r--r--dln.c173
1 files changed, 111 insertions, 62 deletions
diff --git a/dln.c b/dln.c
index 77bfe91b28..89f16b54f0 100644
--- a/dln.c
+++ b/dln.c
@@ -76,6 +76,12 @@ void *xrealloc();
# include <unistd.h>
#endif
+bool
+dln_supported_p(void)
+{
+ return true;
+}
+
#ifndef dln_loaderror
static void
dln_loaderror(const char *format, ...)
@@ -107,36 +113,45 @@ dln_loaderror(const char *format, ...)
#endif
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
-static size_t
-init_funcname_len(const char **file)
+struct string_part {
+ const char *ptr;
+ size_t len;
+};
+
+static struct string_part
+init_funcname_len(const char *file)
{
- const char *p = *file, *base, *dot = NULL;
+ const char *p = file, *base, *dot = NULL;
/* Load the file as an object one */
for (base = p; *p; p++) { /* Find position of last '/' */
if (*p == '.' && !dot) dot = p;
if (isdirsep(*p)) base = p+1, dot = NULL;
}
- *file = base;
/* Delete suffix if it exists */
- return (dot ? dot : p) - base;
+ const size_t len = (dot ? dot : p) - base;
+ return (struct string_part){base, len};
+}
+
+static inline char *
+concat_funcname(char *buf, const char *prefix, size_t plen, const struct string_part base)
+{
+ if (!buf) {
+ dln_memerror();
+ }
+ memcpy(buf, prefix, plen);
+ memcpy(buf + plen, base.ptr, base.len);
+ buf[plen + base.len] = '\0';
+ return buf;
}
-static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
-
-#define init_funcname(buf, file) do {\
- const char *base = (file);\
- const size_t flen = init_funcname_len(&base);\
- const size_t plen = sizeof(funcname_prefix);\
- char *const tmp = ALLOCA_N(char, plen+flen+1);\
- if (!tmp) {\
- dln_memerror();\
- }\
- memcpy(tmp, funcname_prefix, plen);\
- memcpy(tmp+plen, base, flen);\
- tmp[plen+flen] = '\0';\
- *(buf) = tmp;\
+#define build_funcname(prefix, buf, file) do {\
+ const struct string_part f = init_funcname_len(file);\
+ const size_t plen = sizeof(prefix "") - 1;\
+ *(buf) = concat_funcname(ALLOCA_N(char, plen+f.len+1), prefix, plen, f);\
} while (0)
+
+#define init_funcname(buf, file) build_funcname(FUNCNAME_PREFIX, buf, file)
#endif
#ifdef USE_DLN_DLOPEN
@@ -185,7 +200,6 @@ dln_strerror(char *message, size_t size)
}
return message;
}
-#define dln_strerror() dln_strerror(message, sizeof message)
#elif defined USE_DLN_DLOPEN
static const char *
dln_strerror(void)
@@ -272,13 +286,15 @@ rb_w32_check_imported(HMODULE ext, HMODULE mine)
static bool
dln_incompatible_func(void *handle, const char *funcname, void *const fp, const char **libname)
{
- Dl_info dli;
void *ex = dlsym(handle, funcname);
if (!ex) return false;
if (ex == fp) return false;
+# if defined(HAVE_DLADDR)
+ Dl_info dli;
if (dladdr(ex, &dli)) {
*libname = dli.dli_fname;
}
+# endif
return true;
}
@@ -328,16 +344,13 @@ dln_disable_dlclose(void)
#endif
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
-static void *
-dln_open(const char *file)
+void *
+dln_open(const char *file, char *error, size_t size)
{
static const char incompatible[] = "incompatible library version";
- const char *error = NULL;
void *handle;
#if defined(_WIN32)
- char message[1024];
-
/* Convert the file path to wide char */
WCHAR *winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
if (!winfile) {
@@ -349,15 +362,15 @@ dln_open(const char *file)
free(winfile);
if (!handle) {
- error = dln_strerror();
- goto failed;
+ strlcpy(error, dln_strerror(error, size), size);
+ return NULL;
}
# if defined(RUBY_EXPORT)
if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
FreeLibrary(handle);
- error = incompatible;
- goto failed;
+ strlcpy(error, incompatible, size);
+ return NULL;
}
# endif
@@ -376,8 +389,8 @@ dln_open(const char *file)
/* Load file */
handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL);
if (handle == NULL) {
- error = dln_strerror();
- goto failed;
+ strlcpy(error, dln_strerror(), size);
+ return NULL;
}
# if defined(RUBY_EXPORT)
@@ -399,11 +412,15 @@ dln_open(const char *file)
libruby_name = tmp;
}
dlclose(handle);
+
if (libruby_name) {
- dln_loaderror("linked to incompatible %s - %s", libruby_name, file);
+ snprintf(error, size, "linked to incompatible %s - %s", libruby_name, file);
+ }
+ else {
+ strlcpy(error, incompatible, size);
}
- error = incompatible;
- goto failed;
+
+ return NULL;
}
}
}
@@ -411,41 +428,68 @@ dln_open(const char *file)
#endif
return handle;
-
- failed:
- dln_loaderror("%s - %s", error, file);
}
-static void *
+void *
dln_sym(void *handle, const char *symbol)
{
- void *func;
- const char *error;
-
#if defined(_WIN32)
- char message[1024];
+ return GetProcAddress(handle, symbol);
+#elif defined(USE_DLN_DLOPEN)
+ return dlsym(handle, symbol);
+#endif
+}
- func = GetProcAddress(handle, symbol);
- if (func == NULL) {
- error = dln_strerror();
- goto failed;
- }
+static void *
+dln_sym_func(void *handle, const char *symbol)
+{
+ void *func = dln_sym(handle, symbol);
-#elif defined(USE_DLN_DLOPEN)
- func = dlsym(handle, symbol);
if (func == NULL) {
+ const char *error;
+#if defined(_WIN32)
+ char message[1024];
+ error = dln_strerror(message, sizeof(message));
+#elif defined(USE_DLN_DLOPEN)
const size_t errlen = strlen(error = dln_strerror()) + 1;
error = memcpy(ALLOCA_N(char, errlen), error, errlen);
- goto failed;
- }
#endif
-
+ dln_loaderror("%s - %s", error, symbol);
+ }
return func;
-
- failed:
- dln_loaderror("%s - %s", error, symbol);
}
+
+#define dln_sym_callable(rettype, argtype, handle, symbol) \
+ (*(rettype (*)argtype)dln_sym_func(handle, symbol))
+#endif
+
+void *
+dln_symbol(void *handle, const char *symbol)
+{
+#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
+ if (EXTERNAL_PREFIX[0]) {
+ const size_t symlen = strlen(symbol);
+ char *const tmp = ALLOCA_N(char, symlen + sizeof(EXTERNAL_PREFIX));
+ if (!tmp) dln_memerror();
+ memcpy(tmp, EXTERNAL_PREFIX, sizeof(EXTERNAL_PREFIX) - 1);
+ memcpy(tmp + sizeof(EXTERNAL_PREFIX) - 1, symbol, symlen + 1);
+ symbol = tmp;
+ }
+ if (handle == NULL) {
+# if defined(USE_DLN_DLOPEN)
+ handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
+# elif defined(_WIN32)
+ handle = rb_libruby_handle();
+# else
+ return NULL;
+# endif
+ }
+ return dln_sym(handle, symbol);
+#else
+ return NULL;
#endif
+}
+
#if defined(RUBY_DLN_CHECK_ABI) && defined(USE_DLN_DLOPEN)
static bool
@@ -460,22 +504,27 @@ void *
dln_load(const char *file)
{
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
- void *handle = dln_open(file);
+ char error[1024];
+ void *handle = dln_open(file, error, sizeof(error));
+
+ if (handle == NULL) {
+ dln_loaderror("%s - %s", error, file);
+ }
#ifdef RUBY_DLN_CHECK_ABI
- unsigned long long (*abi_version_fct)(void) = (unsigned long long(*)(void))dln_sym(handle, "ruby_abi_version");
- unsigned long long binary_abi_version = (*abi_version_fct)();
- if (binary_abi_version != ruby_abi_version() && abi_check_enabled_p()) {
+ typedef unsigned long long abi_version_number;
+ abi_version_number binary_abi_version =
+ dln_sym_callable(abi_version_number, (void), handle, EXTERNAL_PREFIX "ruby_abi_version")();
+ if (binary_abi_version != RUBY_ABI_VERSION && abi_check_enabled_p()) {
dln_loaderror("incompatible ABI version of binary - %s", file);
}
#endif
char *init_fct_name;
init_funcname(&init_fct_name, file);
- void (*init_fct)(void) = (void(*)(void))dln_sym(handle, init_fct_name);
/* Call the init code */
- (*init_fct)();
+ dln_sym_callable(void, (void), handle, init_fct_name)();
return handle;