Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Common Portability Library
4 : * Purpose: Fetch a function pointer from a shared library / DLL.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "cpl_conv.h"
16 :
17 : #include <cstddef>
18 :
19 : #include "cpl_config.h"
20 : #include "cpl_error.h"
21 : #include "cpl_string.h"
22 :
23 : /* ==================================================================== */
24 : /* Unix Implementation */
25 : /* ==================================================================== */
26 :
27 : /* MinGW32 might define HAVE_DLFCN_H, so skip the unix implementation */
28 : #if defined(HAVE_DLFCN_H) && !defined(_WIN32)
29 :
30 : #define GOT_GETSYMBOL
31 :
32 : #include <dlfcn.h>
33 :
34 : /************************************************************************/
35 : /* CPLGetSymbol() */
36 : /************************************************************************/
37 :
38 : /**
39 : * Fetch a function pointer from a shared library / DLL.
40 : *
41 : * This function is meant to abstract access to shared libraries and
42 : * DLLs and performs functions similar to dlopen()/dlsym() on Unix and
43 : * LoadLibrary() / GetProcAddress() on Windows.
44 : *
45 : * If no support for loading entry points from a shared library is available
46 : * this function will always return NULL. Rules on when this function
47 : * issues a CPLError() or not are not currently well defined, and will have
48 : * to be resolved in the future.
49 : *
50 : * Currently CPLGetSymbol() doesn't try to:
51 : * <ul>
52 : * <li> prevent the reference count on the library from going up
53 : * for every request, or given any opportunity to unload
54 : * the library.
55 : * <li> Attempt to look for the library in non-standard
56 : * locations.
57 : * <li> Attempt to try variations on the symbol name, like
58 : * pre-pending or post-pending an underscore.
59 : * </ul>
60 : *
61 : * Some of these issues may be worked on in the future.
62 : *
63 : * @param pszLibrary the name of the shared library or DLL containing
64 : * the function. May contain path to file. If not system supplies search
65 : * paths will be used.
66 : * @param pszSymbolName the name of the function to fetch a pointer to.
67 : * @return A pointer to the function if found, or NULL if the function isn't
68 : * found, or the shared library can't be loaded.
69 : */
70 :
71 485 : void *CPLGetSymbol(const char *pszLibrary, const char *pszSymbolName)
72 :
73 : {
74 485 : void *pLibrary = dlopen(pszLibrary, RTLD_LAZY);
75 485 : if (pLibrary == nullptr)
76 : {
77 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", dlerror());
78 0 : return nullptr;
79 : }
80 :
81 485 : void *pSymbol = dlsym(pLibrary, pszSymbolName);
82 :
83 : #if (defined(__APPLE__) && defined(__MACH__))
84 : /* On mach-o systems, C symbols have a leading underscore and depending
85 : * on how dlcompat is configured it may or may not add the leading
86 : * underscore. If dlsym() fails, add an underscore and try again.
87 : */
88 : if (pSymbol == nullptr)
89 : {
90 : char withUnder[256] = {};
91 : snprintf(withUnder, sizeof(withUnder), "_%s", pszSymbolName);
92 : pSymbol = dlsym(pLibrary, withUnder);
93 : }
94 : #endif
95 :
96 485 : if (pSymbol == nullptr)
97 : {
98 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", dlerror());
99 : // Do not call dlclose here. misc.py:misc_6() demonstrates the crash.
100 : // coverity[leaked_storage]
101 0 : return nullptr;
102 : }
103 :
104 : // coverity[leaked_storage] It is not safe to call dlclose.
105 485 : return (pSymbol);
106 : }
107 :
108 : #endif /* def __unix__ && defined(HAVE_DLFCN_H) */
109 :
110 : /* ==================================================================== */
111 : /* Windows Implementation */
112 : /* ==================================================================== */
113 : #if defined(_WIN32)
114 :
115 : #define GOT_GETSYMBOL
116 :
117 : #include <windows.h>
118 :
119 : /************************************************************************/
120 : /* CPLGetSymbol() */
121 : /************************************************************************/
122 :
123 : void *CPLGetSymbol(const char *pszLibrary, const char *pszSymbolName)
124 :
125 : {
126 : void *pLibrary = nullptr;
127 : void *pSymbol = nullptr;
128 :
129 : // Avoid error boxes to pop up (#5211, #5525).
130 : UINT uOldErrorMode =
131 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
132 :
133 : #if defined(_MSC_VER) || __MSVCRT_VERSION__ >= 0x0601
134 : if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
135 : {
136 : wchar_t *pwszFilename =
137 : CPLRecodeToWChar(pszLibrary, CPL_ENC_UTF8, CPL_ENC_UCS2);
138 : pLibrary = LoadLibraryW(pwszFilename);
139 : CPLFree(pwszFilename);
140 : }
141 : else
142 : #endif
143 : {
144 : pLibrary = LoadLibraryA(pszLibrary);
145 : }
146 :
147 : if (pLibrary <= (void *)HINSTANCE_ERROR)
148 : {
149 : LPVOID lpMsgBuf = nullptr;
150 : int nLastError = GetLastError();
151 :
152 : // Restore old error mode.
153 : SetErrorMode(uOldErrorMode);
154 :
155 : FormatMessage(
156 : FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
157 : FORMAT_MESSAGE_IGNORE_INSERTS,
158 : nullptr, nLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
159 : reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
160 :
161 : CPLError(CE_Failure, CPLE_AppDefined,
162 : "Can't load requested DLL: %s\n%d: %s", pszLibrary, nLastError,
163 : static_cast<const char *>(lpMsgBuf));
164 : return nullptr;
165 : }
166 :
167 : // Restore old error mode.
168 : SetErrorMode(uOldErrorMode);
169 :
170 : pSymbol = reinterpret_cast<void *>(
171 : GetProcAddress(static_cast<HINSTANCE>(pLibrary), pszSymbolName));
172 :
173 : if (pSymbol == nullptr)
174 : {
175 : CPLError(CE_Failure, CPLE_AppDefined,
176 : "Can't find requested entry point: %s", pszSymbolName);
177 : return nullptr;
178 : }
179 :
180 : return (pSymbol);
181 : }
182 :
183 : #endif // def _WIN32
184 :
185 : /* ==================================================================== */
186 : /* Dummy implementation. */
187 : /* ==================================================================== */
188 :
189 : #ifndef GOT_GETSYMBOL
190 :
191 : /************************************************************************/
192 : /* CPLGetSymbol() */
193 : /* */
194 : /* Dummy implementation. */
195 : /************************************************************************/
196 :
197 : void *CPLGetSymbol(const char *pszLibrary, const char *pszEntryPoint)
198 :
199 : {
200 : CPLDebug("CPL",
201 : "CPLGetSymbol(%s,%s) called. Failed as this is stub"
202 : " implementation.",
203 : pszLibrary, pszEntryPoint);
204 : return nullptr;
205 : }
206 : #endif
|