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 : #include <map>
35 : #include <mutex>
36 :
37 : /************************************************************************/
38 : /* CPLGetSymbol() */
39 : /************************************************************************/
40 :
41 : /**
42 : * Fetch a function pointer from a shared library / DLL.
43 : *
44 : * This function is meant to abstract access to shared libraries and
45 : * DLLs and performs functions similar to dlopen()/dlsym() on Unix and
46 : * LoadLibrary() / GetProcAddress() on Windows.
47 : *
48 : * If no support for loading entry points from a shared library is available
49 : * this function will always return NULL. Rules on when this function
50 : * issues a CPLError() or not are not currently well defined, and will have
51 : * to be resolved in the future.
52 : *
53 : * Currently CPLGetSymbol() doesn't try to:
54 : * <ul>
55 : * <li> prevent the reference count on the library from going up
56 : * for every request, or given any opportunity to unload
57 : * the library.
58 : * <li> Attempt to look for the library in non-standard
59 : * locations.
60 : * <li> Attempt to try variations on the symbol name, like
61 : * pre-pending or post-pending an underscore.
62 : * </ul>
63 : *
64 : * Some of these issues may be worked on in the future.
65 : *
66 : * @param pszLibrary the name of the shared library or DLL containing
67 : * the function. May contain path to file. If not system supplies search
68 : * paths will be used.
69 : * @param pszSymbolName the name of the function to fetch a pointer to.
70 : * @return A pointer to the function if found, or NULL if the function isn't
71 : * found, or the shared library can't be loaded.
72 : */
73 :
74 540 : void *CPLGetSymbol(const char *pszLibrary, const char *pszSymbolName)
75 :
76 : {
77 : static std::mutex mutex;
78 540 : static std::map<std::string, void *> mapLibraryNameToHandle;
79 1080 : std::lock_guard oLock(mutex);
80 :
81 : void *pLibrary;
82 540 : const char *pszNonNullLibrary = pszLibrary ? pszLibrary : "";
83 540 : auto oIter = mapLibraryNameToHandle.find(pszNonNullLibrary);
84 540 : if (oIter == mapLibraryNameToHandle.end())
85 : {
86 540 : pLibrary = dlopen(pszLibrary, RTLD_LAZY);
87 540 : if (pLibrary == nullptr)
88 : {
89 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", dlerror());
90 0 : return nullptr;
91 : }
92 540 : mapLibraryNameToHandle[pszNonNullLibrary] = pLibrary;
93 : }
94 : else
95 : {
96 0 : pLibrary = oIter->second;
97 : }
98 :
99 540 : void *pSymbol = dlsym(pLibrary, pszSymbolName);
100 :
101 : #if (defined(__APPLE__) && defined(__MACH__))
102 : /* On mach-o systems, C symbols have a leading underscore and depending
103 : * on how dlcompat is configured it may or may not add the leading
104 : * underscore. If dlsym() fails, add an underscore and try again.
105 : */
106 : if (pSymbol == nullptr)
107 : {
108 : char withUnder[256] = {};
109 : snprintf(withUnder, sizeof(withUnder), "_%s", pszSymbolName);
110 : pSymbol = dlsym(pLibrary, withUnder);
111 : }
112 : #endif
113 :
114 540 : if (pSymbol == nullptr)
115 : {
116 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", dlerror());
117 0 : return nullptr;
118 : }
119 :
120 540 : return (pSymbol);
121 : }
122 :
123 : #endif /* def __unix__ && defined(HAVE_DLFCN_H) */
124 :
125 : /* ==================================================================== */
126 : /* Windows Implementation */
127 : /* ==================================================================== */
128 : #if defined(_WIN32)
129 :
130 : #define GOT_GETSYMBOL
131 :
132 : #include <windows.h>
133 :
134 : /************************************************************************/
135 : /* CPLGetSymbol() */
136 : /************************************************************************/
137 :
138 : void *CPLGetSymbol(const char *pszLibrary, const char *pszSymbolName)
139 :
140 : {
141 : void *pLibrary = nullptr;
142 : void *pSymbol = nullptr;
143 :
144 : // Avoid error boxes to pop up (#5211, #5525).
145 : UINT uOldErrorMode =
146 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
147 :
148 : #if defined(_MSC_VER) || __MSVCRT_VERSION__ >= 0x0601
149 : if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
150 : {
151 : wchar_t *pwszFilename =
152 : CPLRecodeToWChar(pszLibrary, CPL_ENC_UTF8, CPL_ENC_UCS2);
153 : pLibrary = LoadLibraryW(pwszFilename);
154 : CPLFree(pwszFilename);
155 : }
156 : else
157 : #endif
158 : {
159 : pLibrary = LoadLibraryA(pszLibrary);
160 : }
161 :
162 : if (pLibrary <= (void *)HINSTANCE_ERROR)
163 : {
164 : LPVOID lpMsgBuf = nullptr;
165 : int nLastError = GetLastError();
166 :
167 : // Restore old error mode.
168 : SetErrorMode(uOldErrorMode);
169 :
170 : FormatMessage(
171 : FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
172 : FORMAT_MESSAGE_IGNORE_INSERTS,
173 : nullptr, nLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
174 : reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
175 :
176 : CPLError(CE_Failure, CPLE_AppDefined,
177 : "Can't load requested DLL: %s\n%d: %s", pszLibrary, nLastError,
178 : static_cast<const char *>(lpMsgBuf));
179 : return nullptr;
180 : }
181 :
182 : // Restore old error mode.
183 : SetErrorMode(uOldErrorMode);
184 :
185 : pSymbol = reinterpret_cast<void *>(
186 : GetProcAddress(static_cast<HINSTANCE>(pLibrary), pszSymbolName));
187 :
188 : if (pSymbol == nullptr)
189 : {
190 : CPLError(CE_Failure, CPLE_AppDefined,
191 : "Can't find requested entry point: %s", pszSymbolName);
192 : return nullptr;
193 : }
194 :
195 : return (pSymbol);
196 : }
197 :
198 : #endif // def _WIN32
199 :
200 : /* ==================================================================== */
201 : /* Dummy implementation. */
202 : /* ==================================================================== */
203 :
204 : #ifndef GOT_GETSYMBOL
205 :
206 : /************************************************************************/
207 : /* CPLGetSymbol() */
208 : /* */
209 : /* Dummy implementation. */
210 : /************************************************************************/
211 :
212 : void *CPLGetSymbol(const char *pszLibrary, const char *pszEntryPoint)
213 :
214 : {
215 : CPLDebug("CPL",
216 : "CPLGetSymbol(%s,%s) called. Failed as this is stub"
217 : " implementation.",
218 : pszLibrary, pszEntryPoint);
219 : return nullptr;
220 : }
221 : #endif
|