Annotation of parser3/src/lib/ltdl/loaders/loadlibrary.c, revision 1.2
1.1 moko 1: /* loader-loadlibrary.c -- dynamic linking for Win32
2:
1.2 ! moko 3: Copyright (C) 1998-2000, 2004-2008, 2010-2019, 2021-2024 Free
! 4: Software Foundation, Inc.
1.1 moko 5: Written by Thomas Tanner, 1998
6:
7: NOTE: The canonical source of this file is maintained with the
8: GNU Libtool package. Report bugs to bug-libtool@gnu.org.
9:
10: GNU Libltdl is free software; you can redistribute it and/or
11: modify it under the terms of the GNU Lesser General Public
12: License as published by the Free Software Foundation; either
13: version 2 of the License, or (at your option) any later version.
14:
15: As a special exception to the GNU Lesser General Public License,
16: if you distribute this file as part of a program or library that
17: is built using GNU Libtool, you may include this file under the
18: same distribution terms that you use for the rest of that program.
19:
20: GNU Libltdl is distributed in the hope that it will be useful,
21: but WITHOUT ANY WARRANTY; without even the implied warranty of
22: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23: GNU Lesser General Public License for more details.
24:
25: You should have received a copy of the GNU Lesser General Public
1.2 ! moko 26: License along with GNU Libltdl. If not, see <https://www.gnu.org/licenses/>.
1.1 moko 27: */
28:
29: #include "lt__private.h"
30: #include "lt_dlloader.h"
31:
1.2 ! moko 32: #if defined __CYGWIN__
1.1 moko 33: # include <sys/cygwin.h>
34: #endif
35:
36: /* Use the preprocessor to rename non-static symbols to avoid namespace
37: collisions when the loader code is statically linked into libltdl.
38: Use the "<module_name>_LTX_" prefix so that the symbol addresses can
39: be fetched from the preloaded symbol list by lt_dlsym(): */
40: #define get_vtable loadlibrary_LTX_get_vtable
41:
42: LT_BEGIN_C_DECLS
43: LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
44: LT_END_C_DECLS
45:
46:
47: /* Boilerplate code to set up the vtable for hooking this loader into
48: libltdl's loader list: */
49: static int vl_exit (lt_user_data loader_data);
50: static lt_module vm_open (lt_user_data loader_data, const char *filename,
51: lt_dladvise advise);
52: static int vm_close (lt_user_data loader_data, lt_module module);
53: static void * vm_sym (lt_user_data loader_data, lt_module module,
54: const char *symbolname);
55:
56: static lt_dlinterface_id iface_id = 0;
57: static lt_dlvtable *vtable = 0;
58:
59: /* Return the vtable for this loader, only the name and sym_prefix
60: attributes (plus the virtual function implementations, obviously)
61: change between loaders. */
62: lt_dlvtable *
63: get_vtable (lt_user_data loader_data)
64: {
65: if (!vtable)
66: {
67: vtable = (lt_dlvtable *) lt__zalloc (sizeof *vtable);
68: iface_id = lt_dlinterface_register ("ltdl loadlibrary", NULL);
69: }
70:
71: if (vtable && !vtable->name)
72: {
73: vtable->name = "lt_loadlibrary";
74: vtable->module_open = vm_open;
75: vtable->module_close = vm_close;
76: vtable->find_sym = vm_sym;
77: vtable->dlloader_exit = vl_exit;
78: vtable->dlloader_data = loader_data;
79: vtable->priority = LT_DLLOADER_APPEND;
80: }
81:
82: if (vtable && (vtable->dlloader_data != loader_data))
83: {
84: LT__SETERROR (INIT_LOADER);
85: return 0;
86: }
87:
88: return vtable;
89: }
90:
91:
92:
93: /* --- IMPLEMENTATION --- */
94:
95:
96: #include <windows.h>
97:
98: #define LOCALFREE(mem) LT_STMT_START { \
99: if (mem) { LocalFree ((void *)mem); mem = NULL; } } LT_STMT_END
100: #define LOADLIB__SETERROR(errmsg) LT__SETERRORSTR (loadlibraryerror (errmsg))
101: #define LOADLIB_SETERROR(errcode) LOADLIB__SETERROR (LT__STRERROR (errcode))
102:
103: static const char *loadlibraryerror (const char *default_errmsg);
104: static DWORD WINAPI wrap_getthreaderrormode (void);
105: static DWORD WINAPI fallback_getthreaderrormode (void);
106: static BOOL WINAPI wrap_setthreaderrormode (DWORD mode, DWORD *oldmode);
107: static BOOL WINAPI fallback_setthreaderrormode (DWORD mode, DWORD *oldmode);
108:
109: typedef DWORD (WINAPI getthreaderrormode_type) (void);
110: typedef BOOL (WINAPI setthreaderrormode_type) (DWORD, DWORD *);
111:
112: static getthreaderrormode_type *getthreaderrormode = wrap_getthreaderrormode;
113: static setthreaderrormode_type *setthreaderrormode = wrap_setthreaderrormode;
114: static char *error_message = 0;
115:
116:
117: /* A function called through the vtable when this loader is no
118: longer needed by the application. */
119: static int
1.2 ! moko 120: vl_exit (lt_user_data loader_data LT__UNUSED)
1.1 moko 121: {
122: vtable = NULL;
123: LOCALFREE (error_message);
124: return 0;
125: }
126:
127: /* A function called through the vtable to open a module with this
128: loader. Returns an opaque representation of the newly opened
129: module for processing with this loader's other vtable functions. */
130: static lt_module
1.2 ! moko 131: vm_open (lt_user_data loader_data LT__UNUSED, const char *filename,
! 132: lt_dladvise advise LT__UNUSED)
1.1 moko 133: {
134: lt_module module = 0;
135: char *ext;
136: char wpath[MAX_PATH];
137: size_t len;
138:
139: if (!filename)
140: {
141: /* Get the name of main module */
142: *wpath = 0;
143: GetModuleFileName (NULL, wpath, sizeof (wpath));
144: filename = wpath;
145: }
146: else
147: {
148: len = LT_STRLEN (filename);
149:
150: if (len >= MAX_PATH)
151: {
152: LT__SETERROR (CANNOT_OPEN);
153: return 0;
154: }
155:
156: #if HAVE_DECL_CYGWIN_CONV_PATH
157: if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, filename, wpath, MAX_PATH))
158: {
159: LT__SETERROR (CANNOT_OPEN);
160: return 0;
161: }
162: len = 0;
1.2 ! moko 163: #elif defined __CYGWIN__
1.1 moko 164: cygwin_conv_to_full_win32_path (filename, wpath);
165: len = 0;
166: #else
167: strcpy(wpath, filename);
168: #endif
169:
170: ext = strrchr (wpath, '.');
171: if (!ext)
172: {
1.2 ! moko 173: /* Append a '.' to stop Windows from adding an
! 174: implicit '.dll' extension. */
1.1 moko 175: if (!len)
176: len = strlen (wpath);
177:
178: if (len + 1 >= MAX_PATH)
179: {
180: LT__SETERROR (CANNOT_OPEN);
181: return 0;
182: }
183:
184: wpath[len] = '.';
185: wpath[len+1] = '\0';
186: }
187: }
188:
189: {
190: /* Silence dialog from LoadLibrary on some failures. */
191: DWORD errormode = getthreaderrormode ();
192: DWORD last_error;
193:
194: setthreaderrormode (errormode | SEM_FAILCRITICALERRORS, NULL);
195:
196: module = LoadLibrary (wpath);
197:
198: /* Restore the error mode. */
199: last_error = GetLastError ();
200: setthreaderrormode (errormode, NULL);
201: SetLastError (last_error);
202: }
203:
204: /* libltdl expects this function to fail if it is unable
205: to physically load the library. Sadly, LoadLibrary
206: will search the loaded libraries for a match and return
207: one of them if the path search load fails.
208:
209: We check whether LoadLibrary is returning a handle to
210: an already loaded module, and simulate failure if we
211: find one. */
212: {
213: lt_dlhandle cur = 0;
214:
215: while ((cur = lt_dlhandle_iterate (iface_id, cur)))
216: {
217: if (!cur->module)
218: {
219: cur = 0;
220: break;
221: }
222:
223: if (cur->module == module)
224: {
225: break;
226: }
227: }
228:
229: if (!module)
230: LOADLIB_SETERROR (CANNOT_OPEN);
231: else if (cur)
232: {
233: LT__SETERROR (CANNOT_OPEN);
234: module = 0;
235: }
236: }
237:
238: return module;
239: }
240:
241:
242: /* A function called through the vtable when a particular module
243: should be unloaded. */
244: static int
1.2 ! moko 245: vm_close (lt_user_data loader_data LT__UNUSED, lt_module module)
1.1 moko 246: {
247: int errors = 0;
248:
249: if (FreeLibrary ((HMODULE) module) == 0)
250: {
251: LOADLIB_SETERROR (CANNOT_CLOSE);
252: ++errors;
253: }
254:
255: return errors;
256: }
257:
258:
259: /* A function called through the vtable to get the address of
260: a symbol loaded from a particular module. */
261: static void *
1.2 ! moko 262: vm_sym (lt_user_data loader_data LT__UNUSED, lt_module module, const char *name)
1.1 moko 263: {
264: void *address = (void *) GetProcAddress ((HMODULE) module, name);
265:
266: if (!address)
267: {
268: LOADLIB_SETERROR (SYMBOL_NOT_FOUND);
269: }
270:
271: return address;
272: }
273:
274:
275:
276: /* --- HELPER FUNCTIONS --- */
277:
278:
279: /* Return the windows error message, or the passed in error message on
280: failure. */
281: static const char *
282: loadlibraryerror (const char *default_errmsg)
283: {
284: size_t len;
285: LOCALFREE (error_message);
286:
287: FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
288: FORMAT_MESSAGE_FROM_SYSTEM |
289: FORMAT_MESSAGE_IGNORE_INSERTS,
290: NULL,
291: GetLastError (),
292: 0,
293: (char *) &error_message,
294: 0, NULL);
295:
296: /* Remove trailing CRNL */
297: len = LT_STRLEN (error_message);
298: if (len && error_message[len - 1] == '\n')
299: error_message[--len] = LT_EOS_CHAR;
300: if (len && error_message[len - 1] == '\r')
301: error_message[--len] = LT_EOS_CHAR;
302:
303: return len ? error_message : default_errmsg;
304: }
305:
1.2 ! moko 306: /* A function called through the getthreaderrormode variable that checks
1.1 moko 307: if the system supports GetThreadErrorMode (or GetErrorMode) and arranges
308: for it or a fallback implementation to be called directly in the future.
309: The selected version is then called. */
310: static DWORD WINAPI
311: wrap_getthreaderrormode (void)
312: {
313: HMODULE kernel32 = GetModuleHandleA ("kernel32.dll");
314: getthreaderrormode
315: = (getthreaderrormode_type *) GetProcAddress (kernel32,
316: "GetThreadErrorMode");
317: if (!getthreaderrormode)
318: getthreaderrormode
319: = (getthreaderrormode_type *) GetProcAddress (kernel32,
320: "GetErrorMode");
321: if (!getthreaderrormode)
322: getthreaderrormode = fallback_getthreaderrormode;
323: return getthreaderrormode ();
324: }
325:
326: /* A function called through the getthreaderrormode variable for cases
327: where the system does not support GetThreadErrorMode or GetErrorMode */
328: static DWORD WINAPI
329: fallback_getthreaderrormode (void)
330: {
331: /* Prior to Windows Vista, the only way to get the current error
332: mode was to set a new one. In our case, we are setting a new
333: error mode right after "getting" it while ignoring the error
334: mode in effect when setting the new error mode, so that's
335: fairly ok. */
336: return (DWORD) SetErrorMode (SEM_FAILCRITICALERRORS);
337: }
338:
1.2 ! moko 339: /* A function called through the setthreaderrormode variable that checks
1.1 moko 340: if the system supports SetThreadErrorMode and arranges for it or a
341: fallback implementation to be called directly in the future.
342: The selected version is then called. */
343: static BOOL WINAPI
344: wrap_setthreaderrormode (DWORD mode, DWORD *oldmode)
345: {
346: HMODULE kernel32 = GetModuleHandleA ("kernel32.dll");
347: setthreaderrormode
348: = (setthreaderrormode_type *) GetProcAddress (kernel32,
349: "SetThreadErrorMode");
350: if (!setthreaderrormode)
351: setthreaderrormode = fallback_setthreaderrormode;
352: return setthreaderrormode (mode, oldmode);
353: }
354:
355: /* A function called through the setthreaderrormode variable for cases
356: where the system does not support SetThreadErrorMode. */
357: static BOOL WINAPI
358: fallback_setthreaderrormode (DWORD mode, DWORD *oldmode)
359: {
360: /* Prior to Windows 7, there was no way to set the thread local error
361: mode, so set the process global error mode instead. */
362: DWORD old = (DWORD) SetErrorMode (mode);
363: if (oldmode)
364: *oldmode = old;
365: return TRUE;
366: }
E-mail: