mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 eba90bc034
			
		
	
	
		eba90bc034
		
			
		
	
	
	
	
		
			
			``` compiling ..../ruby/ruby/dln.c ..../ruby/ruby/dln.c:108:1: warning: unused function 'init_funcname_len' [-Wunused-function] init_funcname_len(const char **file) ^ ..../ruby/ruby/dln.c:122:19: warning: unused variable 'funcname_prefix' [-Wunused-const-variable] static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX; ^ 2 warnings generated. ```
		
			
				
	
	
		
			426 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			426 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**********************************************************************
 | |
| 
 | |
|   dln.c -
 | |
| 
 | |
|   $Author$
 | |
|   created at: Tue Jan 18 17:05:06 JST 1994
 | |
| 
 | |
|   Copyright (C) 1993-2007 Yukihiro Matsumoto
 | |
| 
 | |
| **********************************************************************/
 | |
| 
 | |
| #ifdef RUBY_EXPORT
 | |
| #include "ruby/ruby.h"
 | |
| #define dln_notimplement rb_notimplement
 | |
| #define dln_memerror rb_memerror
 | |
| #define dln_exit rb_exit
 | |
| #define dln_loaderror rb_loaderror
 | |
| #else
 | |
| #define dln_notimplement --->>> dln not implemented <<<---
 | |
| #define dln_memerror abort
 | |
| #define dln_exit exit
 | |
| static void dln_loaderror(const char *format, ...);
 | |
| #endif
 | |
| #include "dln.h"
 | |
| #include "internal.h"
 | |
| #include "internal/compilers.h"
 | |
| 
 | |
| #ifdef HAVE_STDLIB_H
 | |
| # include <stdlib.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(HAVE_ALLOCA_H)
 | |
| #include <alloca.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_STRING_H
 | |
| # include <string.h>
 | |
| #else
 | |
| # include <strings.h>
 | |
| #endif
 | |
| 
 | |
| #ifndef xmalloc
 | |
| void *xmalloc();
 | |
| void *xcalloc();
 | |
| void *xrealloc();
 | |
| #endif
 | |
| 
 | |
| #undef free
 | |
| #define free(x) xfree(x)
 | |
| 
 | |
| #include <stdio.h>
 | |
| #if defined(_WIN32)
 | |
| #include "missing/file.h"
 | |
| #endif
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| 
 | |
| #ifndef S_ISDIR
 | |
| #   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_SYS_PARAM_H
 | |
| # include <sys/param.h>
 | |
| #endif
 | |
| #ifndef MAXPATHLEN
 | |
| # define MAXPATHLEN 1024
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_UNISTD_H
 | |
| # include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #ifndef _WIN32
 | |
| char *getenv();
 | |
| #endif
 | |
| 
 | |
| #ifndef dln_loaderror
 | |
| static void
 | |
| dln_loaderror(const char *format, ...)
 | |
| {
 | |
|     va_list ap;
 | |
|     va_start(ap, format);
 | |
|     vfprintf(stderr, format, ap);
 | |
|     va_end(ap);
 | |
|     abort();
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(HAVE_DLOPEN) && !defined(_AIX) && !defined(_UNICOSMP)
 | |
| /* dynamic load with dlopen() */
 | |
| # define USE_DLN_DLOPEN
 | |
| #endif
 | |
| 
 | |
| #if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT)
 | |
| # define EXTERNAL_PREFIX "_"
 | |
| #else
 | |
| # define EXTERNAL_PREFIX ""
 | |
| #endif
 | |
| #define FUNCNAME_PREFIX EXTERNAL_PREFIX"Init_"
 | |
| 
 | |
| #if defined __CYGWIN__ || defined DOSISH
 | |
| #define isdirsep(x) ((x) == '/' || (x) == '\\')
 | |
| #else
 | |
| #define isdirsep(x) ((x) == '/')
 | |
| #endif
 | |
| 
 | |
| #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
 | |
| static size_t
 | |
| init_funcname_len(const char **file)
 | |
| {
 | |
|     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;
 | |
| }
 | |
| 
 | |
| 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;\
 | |
| } while (0)
 | |
| #endif
 | |
| 
 | |
| #ifdef USE_DLN_DLOPEN
 | |
| # include <dlfcn.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(_AIX)
 | |
| #include <ctype.h>	/* for isdigit()	*/
 | |
| #include <errno.h>	/* for global errno	*/
 | |
| #include <sys/ldr.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef NeXT
 | |
| #if NS_TARGET_MAJOR < 4
 | |
| #include <mach-o/rld.h>
 | |
| #else
 | |
| #include <mach-o/dyld.h>
 | |
| #ifndef NSLINKMODULE_OPTION_BINDNOW
 | |
| #define NSLINKMODULE_OPTION_BINDNOW 1
 | |
| #endif
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #ifdef _WIN32
 | |
| #include <windows.h>
 | |
| #include <imagehlp.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef _WIN32
 | |
| static const char *
 | |
| dln_strerror(char *message, size_t size)
 | |
| {
 | |
|     int error = GetLastError();
 | |
|     char *p = message;
 | |
|     size_t len = snprintf(message, size, "%d: ", error);
 | |
| 
 | |
| #define format_message(sublang) FormatMessage(\
 | |
| 	FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,	\
 | |
| 	NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)),		\
 | |
| 	message + len, size - len, NULL)
 | |
|     if (format_message(SUBLANG_ENGLISH_US) == 0)
 | |
| 	format_message(SUBLANG_DEFAULT);
 | |
|     for (p = message + len; *p; p++) {
 | |
| 	if (*p == '\n' || *p == '\r')
 | |
| 	    *p = ' ';
 | |
|     }
 | |
|     return message;
 | |
| }
 | |
| #define dln_strerror() dln_strerror(message, sizeof message)
 | |
| #elif defined USE_DLN_DLOPEN
 | |
| static const char *
 | |
| dln_strerror(void)
 | |
| {
 | |
|     return (char*)dlerror();
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(_AIX)
 | |
| static void
 | |
| aix_loaderror(const char *pathname)
 | |
| {
 | |
|     char *message[1024], errbuf[1024];
 | |
|     int i;
 | |
| #define ERRBUF_APPEND(s) strlcat(errbuf, (s), sizeof(errbuf))
 | |
|     snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname);
 | |
| 
 | |
|     if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) {
 | |
| 	ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
 | |
| 	ERRBUF_APPEND("/usr/sbin/execerror ruby ");
 | |
| 	for (i=0; message[i]; i++) {
 | |
| 	    ERRBUF_APPEND("\"");
 | |
| 	    ERRBUF_APPEND(message[i]);
 | |
| 	    ERRBUF_APPEND("\" ");
 | |
| 	}
 | |
| 	ERRBUF_APPEND("\n");
 | |
|     }
 | |
|     else {
 | |
| 	ERRBUF_APPEND(strerror(errno));
 | |
| 	ERRBUF_APPEND("[loadquery failed]");
 | |
|     }
 | |
|     dln_loaderror("%s", errbuf);
 | |
| }
 | |
| #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);
 | |
| 	for (; piat->u1.Function; piat++, pint++) {
 | |
| 	    static const char prefix[] = "rb_";
 | |
| 	    PIMAGE_IMPORT_BY_NAME pii;
 | |
| 	    const char *name;
 | |
| 
 | |
| 	    if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue;
 | |
| 	    pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
 | |
| 	    name = (const char *)pii->Name;
 | |
| 	    if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
 | |
| 		FARPROC addr = GetProcAddress(mine, name);
 | |
| 		if (addr) return (FARPROC)piat->u1.Function == addr;
 | |
| 	    }
 | |
| 	}
 | |
| 	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; \
 | |
| 	do { \
 | |
| 	    *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
 | |
| 	} while (c); \
 | |
| 	(src) = tmp; \
 | |
|     } while (0)
 | |
| #else
 | |
| #define translit_separator(str) (void)(str)
 | |
| #endif
 | |
| 
 | |
| #ifdef USE_DLN_DLOPEN
 | |
| # include "ruby/internal/stdbool.h"
 | |
| # include "internal/warnings.h"
 | |
| COMPILER_WARNING_PUSH
 | |
| #if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0)
 | |
| COMPILER_WARNING_IGNORED(-Wpedantic)
 | |
| #endif
 | |
| static bool
 | |
| dln_incompatible_library_p(void *handle)
 | |
| {
 | |
|     void *ex = dlsym(handle, EXTERNAL_PREFIX"ruby_xmalloc");
 | |
|     void *const fp = (void *)ruby_xmalloc;
 | |
|     return ex && ex != fp;
 | |
| }
 | |
| COMPILER_WARNING_POP
 | |
| #endif
 | |
| 
 | |
| #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
 | |
| static void *
 | |
| dln_open(const char *file)
 | |
| {
 | |
|     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) {
 | |
| 	dln_memerror();
 | |
|     }
 | |
| 
 | |
|     /* Load file */
 | |
|     handle = LoadLibraryW(winfile);
 | |
|     free(winfile);
 | |
| 
 | |
|     if (!handle) {
 | |
| 	error = dln_strerror();
 | |
| 	goto failed;
 | |
|     }
 | |
| 
 | |
| # if defined(RUBY_EXPORT)
 | |
|     if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
 | |
| 	FreeLibrary(handle);
 | |
| 	error = incompatible;
 | |
| 	goto failed;
 | |
|     }
 | |
| # endif
 | |
| 
 | |
| #elif defined(USE_DLN_DLOPEN)
 | |
| 
 | |
| # ifndef RTLD_LAZY
 | |
| #  define RTLD_LAZY 1
 | |
| # endif
 | |
| # ifdef __INTERIX
 | |
| #  undef RTLD_GLOBAL
 | |
| # endif
 | |
| # ifndef RTLD_GLOBAL
 | |
| #  define RTLD_GLOBAL 0
 | |
| # endif
 | |
| 
 | |
|     /* Load file */
 | |
|     handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL);
 | |
|     if (handle == NULL) {
 | |
|         error = dln_strerror();
 | |
|         goto failed;
 | |
|     }
 | |
| 
 | |
| # if defined(RUBY_EXPORT)
 | |
| 	{
 | |
| 	    if (dln_incompatible_library_p(handle)) {
 | |
| #  if defined(__APPLE__) && \
 | |
|     defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
 | |
|     (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
 | |
| 		/* dlclose() segfaults */
 | |
| 		rb_fatal("%s - %s", incompatible, file);
 | |
| #  else
 | |
| 		dlclose(handle);
 | |
| 		error = incompatible;
 | |
| 		goto failed;
 | |
| #  endif
 | |
| 	    }
 | |
| 	}
 | |
| # endif
 | |
| #endif
 | |
| 
 | |
|     return handle;
 | |
| 
 | |
|   failed:
 | |
|     dln_loaderror("%s - %s", error, file);
 | |
| }
 | |
| 
 | |
| static void *
 | |
| dln_sym(void *handle, const char *symbol)
 | |
| {
 | |
|     void *func;
 | |
|     const char *error;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
|     char message[1024];
 | |
| 
 | |
|     func = GetProcAddress(handle, symbol);
 | |
|     if (func == NULL) {
 | |
|         error = dln_strerror();
 | |
|         goto failed;
 | |
|     }
 | |
| 
 | |
| #elif defined(USE_DLN_DLOPEN)
 | |
|     func = dlsym(handle, symbol);
 | |
|     if (func == NULL) {
 | |
|         const size_t errlen = strlen(error = dln_strerror()) + 1;
 | |
|         error = memcpy(ALLOCA_N(char, errlen), error, errlen);
 | |
|         goto failed;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     return func;
 | |
| 
 | |
|   failed:
 | |
|     dln_loaderror("%s - %s", error, symbol);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void *
 | |
| dln_load(const char *file)
 | |
| {
 | |
| #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
 | |
|     void *handle = dln_open(file);
 | |
| 
 | |
|     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)();
 | |
| 
 | |
|     return handle;
 | |
| 
 | |
| #elif defined(_AIX)
 | |
|     {
 | |
| 	void (*init_fct)(void);
 | |
| 
 | |
| 	init_fct = (void(*)(void))load((char*)file, 1, 0);
 | |
| 	if (init_fct == NULL) {
 | |
| 	    aix_loaderror(file);
 | |
| 	}
 | |
| 	if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
 | |
| 	    aix_loaderror(file);
 | |
| 	}
 | |
| 	(*init_fct)();
 | |
| 	return (void*)init_fct;
 | |
|     }
 | |
| #else
 | |
|     dln_notimplement();
 | |
| #endif
 | |
| 
 | |
|     return 0;			/* dummy return */
 | |
| }
 |