Ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e0ba6b95ab71a441357ed5484e33498)
dln.c
1/**********************************************************************
2
3 dln.c -
4
5 $Author$
6 created at: Tue Jan 18 17:05:06 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#ifdef RUBY_EXPORT
13#include "ruby/ruby.h"
14#define dln_notimplement rb_notimplement
15#define dln_memerror rb_memerror
16#define dln_exit rb_exit
17#define dln_loaderror rb_loaderror
18#else
19#define dln_notimplement --->>> dln not implemented <<<---
20#define dln_memerror abort
21#define dln_exit exit
22static void dln_loaderror(const char *format, ...);
23#endif
24#include "dln.h"
25#include "internal.h"
26#include "internal/compilers.h"
27
28#ifdef HAVE_STDLIB_H
29# include <stdlib.h>
30#endif
31
32#if defined(HAVE_ALLOCA_H)
33#include <alloca.h>
34#endif
35
36#ifdef HAVE_STRING_H
37# include <string.h>
38#else
39# include <strings.h>
40#endif
41
42#ifndef xmalloc
43void *xmalloc();
44void *xcalloc();
45void *xrealloc();
46#endif
47
48#undef free
49#define free(x) xfree(x)
50
51#include <stdio.h>
52#if defined(_WIN32)
53#include "missing/file.h"
54#endif
55#include <sys/types.h>
56#include <sys/stat.h>
57
58#ifndef S_ISDIR
59# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
60#endif
61
62#ifdef HAVE_SYS_PARAM_H
63# include <sys/param.h>
64#endif
65#ifndef MAXPATHLEN
66# define MAXPATHLEN 1024
67#endif
68
69#ifdef HAVE_UNISTD_H
70# include <unistd.h>
71#endif
72
73#ifndef _WIN32
74char *getenv();
75#endif
76
77#ifdef __APPLE__
78# if defined(HAVE_DLOPEN)
79 /* Mac OS X with dlopen (10.3 or later) */
80# define MACOSX_DLOPEN
81# else
82# define MACOSX_DYLD
83# endif
84#endif
85
86#ifndef dln_loaderror
87static void
88dln_loaderror(const char *format, ...)
89{
90 va_list ap;
91 va_start(ap, format);
92 vfprintf(stderr, format, ap);
93 va_end(ap);
94 abort();
95}
96#endif
97
98#if defined(HAVE_DLOPEN) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
99/* dynamic load with dlopen() */
100# define USE_DLN_DLOPEN
101#endif
102
103#if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT) || defined(MACOSX_DYLD)
104# define EXTERNAL_PREFIX "_"
105#else
106# define EXTERNAL_PREFIX ""
107#endif
108#define FUNCNAME_PREFIX EXTERNAL_PREFIX"Init_"
109
110#if defined __CYGWIN__ || defined DOSISH
111#define isdirsep(x) ((x) == '/' || (x) == '\\')
112#else
113#define isdirsep(x) ((x) == '/')
114#endif
115
116static size_t
117init_funcname_len(const char **file)
118{
119 const char *p = *file, *base, *dot = NULL;
120
121 /* Load the file as an object one */
122 for (base = p; *p; p++) { /* Find position of last '/' */
123 if (*p == '.' && !dot) dot = p;
124 if (isdirsep(*p)) base = p+1, dot = NULL;
125 }
126 *file = base;
127 /* Delete suffix if it exists */
128 return (dot ? dot : p) - base;
129}
130
131static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
132
133#define init_funcname(buf, file) do {\
134 const char *base = (file);\
135 const size_t flen = init_funcname_len(&base);\
136 const size_t plen = sizeof(funcname_prefix);\
137 char *const tmp = ALLOCA_N(char, plen+flen+1);\
138 if (!tmp) {\
139 dln_memerror();\
140 }\
141 memcpy(tmp, funcname_prefix, plen);\
142 memcpy(tmp+plen, base, flen);\
143 tmp[plen+flen] = '\0';\
144 *(buf) = tmp;\
145} while (0)
146
147#ifdef USE_DLN_DLOPEN
148# include <dlfcn.h>
149#endif
150
151#ifdef __hpux
152#include <errno.h>
153#include "dl.h"
154#endif
155
156#if defined(_AIX)
157#include <ctype.h> /* for isdigit() */
158#include <errno.h> /* for global errno */
159#include <sys/ldr.h>
160#endif
161
162#ifdef NeXT
163#if NS_TARGET_MAJOR < 4
164#include <mach-o/rld.h>
165#else
166#include <mach-o/dyld.h>
167#ifndef NSLINKMODULE_OPTION_BINDNOW
168#define NSLINKMODULE_OPTION_BINDNOW 1
169#endif
170#endif
171#else
172#ifdef MACOSX_DYLD
173#include <mach-o/dyld.h>
174#endif
175#endif
176
177#ifdef _WIN32
178#include <windows.h>
179#include <imagehlp.h>
180#endif
181
182#ifdef _WIN32
183static const char *
184dln_strerror(char *message, size_t size)
185{
186 int error = GetLastError();
187 char *p = message;
188 size_t len = snprintf(message, size, "%d: ", error);
189
190#define format_message(sublang) FormatMessage(\
191 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
192 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
193 message + len, size - len, NULL)
194 if (format_message(SUBLANG_ENGLISH_US) == 0)
195 format_message(SUBLANG_DEFAULT);
196 for (p = message + len; *p; p++) {
197 if (*p == '\n' || *p == '\r')
198 *p = ' ';
199 }
200 return message;
201}
202#define dln_strerror() dln_strerror(message, sizeof message)
203#elif defined USE_DLN_DLOPEN
204static const char *
205dln_strerror(void)
206{
207 return (char*)dlerror();
208}
209#endif
210
211#if defined(_AIX)
212static void
213aix_loaderror(const char *pathname)
214{
215 char *message[1024], errbuf[1024];
216 int i;
217#define ERRBUF_APPEND(s) strlcat(errbuf, (s), sizeof(errbuf))
218 snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname);
219
220 if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) {
221 ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
222 ERRBUF_APPEND("/usr/sbin/execerror ruby ");
223 for (i=0; message[i]; i++) {
224 ERRBUF_APPEND("\"");
225 ERRBUF_APPEND(message[i]);
226 ERRBUF_APPEND("\" ");
227 }
228 ERRBUF_APPEND("\n");
229 }
230 else {
231 ERRBUF_APPEND(strerror(errno));
232 ERRBUF_APPEND("[loadquery failed]");
233 }
234 dln_loaderror("%s", errbuf);
235}
236#endif
237
238#if defined _WIN32 && defined RUBY_EXPORT
239HANDLE rb_libruby_handle(void);
240
241static int
242rb_w32_check_imported(HMODULE ext, HMODULE mine)
243{
244 ULONG size;
245 const IMAGE_IMPORT_DESCRIPTOR *desc;
246
247 desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
248 if (!desc) return 0;
249 while (desc->Name) {
250 PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics);
251 PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk);
252 for (; piat->u1.Function; piat++, pint++) {
253 static const char prefix[] = "rb_";
254 PIMAGE_IMPORT_BY_NAME pii;
255 const char *name;
256
257 if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue;
258 pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
259 name = (const char *)pii->Name;
260 if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
261 FARPROC addr = GetProcAddress(mine, name);
262 if (addr) return (FARPROC)piat->u1.Function == addr;
263 }
264 }
265 desc++;
266 }
267 return 1;
268}
269#endif
270
271#if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
272#define translit_separator(src) do { \
273 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
274 do { \
275 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
276 } while (c); \
277 (src) = tmp; \
278 } while (0)
279#else
280#define translit_separator(str) (void)(str)
281#endif
282
283#ifdef USE_DLN_DLOPEN
284# include "ruby/internal/stdbool.h"
285# include "internal/warnings.h"
286COMPILER_WARNING_PUSH
287#if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0)
288COMPILER_WARNING_IGNORED(-Wpedantic)
289#endif
290static bool
291dln_incompatible_library_p(void *handle)
292{
293 void *ex = dlsym(handle, EXTERNAL_PREFIX"ruby_xmalloc");
294 void *const fp = (void *)ruby_xmalloc;
295 return ex && ex != fp;
296}
297COMPILER_WARNING_POP
298#endif
299
300void*
301dln_load(const char *file)
302{
303#if (defined _WIN32 || defined USE_DLN_DLOPEN) && defined RUBY_EXPORT
304 static const char incompatible[] = "incompatible library version";
305#endif
306#if defined _WIN32 || defined USE_DLN_DLOPEN
307 const char *error = 0;
308#endif
309
310#if defined _WIN32
311 HINSTANCE handle;
312 WCHAR *winfile;
313 char message[1024];
314 void (*init_fct)(void);
315 char *buf;
316
317 /* Load the file as an object one */
318 init_funcname(&buf, file);
319
320 /* Convert the file path to wide char */
321 winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
322 if (!winfile) {
323 dln_memerror();
324 }
325
326 /* Load file */
327 handle = LoadLibraryW(winfile);
328 free(winfile);
329
330 if (!handle) {
331 error = dln_strerror();
332 goto failed;
333 }
334
335#if defined _WIN32 && defined RUBY_EXPORT
336 if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
337 FreeLibrary(handle);
338 error = incompatible;
339 goto failed;
340 }
341#endif
342
343 if ((init_fct = (void(*)(void))GetProcAddress(handle, buf)) == NULL) {
344 dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
345 }
346
347 /* Call the init code */
348 (*init_fct)();
349 return handle;
350#else
351 char *buf;
352 /* Load the file as an object one */
353 init_funcname(&buf, file);
354 translit_separator(file);
355
356#ifdef USE_DLN_DLOPEN
357#define DLN_DEFINED
358 {
359 void *handle;
360 void (*init_fct)(void);
361
362#ifndef RTLD_LAZY
363# define RTLD_LAZY 1
364#endif
365#ifdef __INTERIX
366# undef RTLD_GLOBAL
367#endif
368#ifndef RTLD_GLOBAL
369# define RTLD_GLOBAL 0
370#endif
371
372 /* Load file */
373 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
374 error = dln_strerror();
375 goto failed;
376 }
377# if defined RUBY_EXPORT
378 {
379 if (dln_incompatible_library_p(handle)) {
380
381# if defined __APPLE__ && \
382 defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
383 (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
384 /* dlclose() segfaults */
385 rb_fatal("%s - %s", incompatible, file);
386# else
387 dlclose(handle);
388 error = incompatible;
389 goto failed;
390# endif
391 }
392 }
393# endif
394
395 init_fct = (void(*)(void))(VALUE)dlsym(handle, buf);
396 if (init_fct == NULL) {
397 const size_t errlen = strlen(error = dln_strerror()) + 1;
398 error = memcpy(ALLOCA_N(char, errlen), error, errlen);
399 dlclose(handle);
400 goto failed;
401 }
402 /* Call the init code */
403 (*init_fct)();
404
405 return handle;
406 }
407#endif /* USE_DLN_DLOPEN */
408
409#ifdef __hpux
410#define DLN_DEFINED
411 {
412 shl_t lib = NULL;
413 int flags;
414 void (*init_fct)(void);
415
416 flags = BIND_DEFERRED;
417 lib = shl_load(file, flags, 0);
418 if (lib == NULL) {
419 extern int errno;
420 dln_loaderror("%s - %s", strerror(errno), file);
421 }
422 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
423 if (init_fct == NULL) {
424 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
425 if (init_fct == NULL) {
426 errno = ENOSYM;
427 dln_loaderror("%s - %s", strerror(ENOSYM), file);
428 }
429 }
430 (*init_fct)();
431 return (void*)lib;
432 }
433#endif /* hpux */
434
435#if defined(_AIX)
436#define DLN_DEFINED
437 {
438 void (*init_fct)(void);
439
440 init_fct = (void(*)(void))load((char*)file, 1, 0);
441 if (init_fct == NULL) {
442 aix_loaderror(file);
443 }
444 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
445 aix_loaderror(file);
446 }
447 (*init_fct)();
448 return (void*)init_fct;
449 }
450#endif /* _AIX */
451
452#if defined(MACOSX_DYLD)
453#define DLN_DEFINED
454/*----------------------------------------------------
455 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
456
457 Special Thanks...
458 Yu tomoak-i@is.aist-nara.ac.jp,
459 Mi hisho@tasihara.nest.or.jp,
460 sunshine@sunshineco.com,
461 and... Miss ARAI Akino(^^;)
462 ----------------------------------------------------*/
463 {
464 int dyld_result;
465 NSObjectFileImage obj_file; /* handle, but not use it */
466 /* "file" is module file name .
467 "buf" is pointer to initial function name with "_" . */
468
469 void (*init_fct)(void);
470
471
472 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
473
474 if (dyld_result != NSObjectFileImageSuccess) {
475 dln_loaderror("Failed to load %.200s", file);
476 }
477
478 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
479
480 /* lookup the initial function */
481 if (!NSIsSymbolNameDefined(buf)) {
482 dln_loaderror("Failed to lookup Init function %.200s",file);
483 }
484 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
485 (*init_fct)();
486
487 return (void*)init_fct;
488 }
489#endif
490
491#ifndef DLN_DEFINED
492 dln_notimplement();
493#endif
494
495#endif
496#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
497 failed:
498 dln_loaderror("%s - %s", error, file);
499#endif
500
501 return 0; /* dummy return */
502}
#define xrealloc
Old name of ruby_xrealloc.
Definition: xmalloc.h:56
#define xmalloc
Old name of ruby_xmalloc.
Definition: xmalloc.h:53
#define xcalloc
Old name of ruby_xcalloc.
Definition: xmalloc.h:55
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition: error.c:3072
#define ALLOCA_N(type, n)
Definition: memory.h:286
C99 shim for <stdbool.h>
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
Definition: gc.c:13665