/src/gdal/port/cplgetsymbol.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | void *CPLGetSymbol(const char *pszLibrary, const char *pszSymbolName) |
75 | | |
76 | 0 | { |
77 | 0 | static std::mutex mutex; |
78 | 0 | static std::map<std::string, void *> mapLibraryNameToHandle; |
79 | 0 | std::lock_guard oLock(mutex); |
80 | |
|
81 | 0 | void *pLibrary; |
82 | 0 | const char *pszNonNullLibrary = pszLibrary ? pszLibrary : ""; |
83 | 0 | auto oIter = mapLibraryNameToHandle.find(pszNonNullLibrary); |
84 | 0 | if (oIter == mapLibraryNameToHandle.end()) |
85 | 0 | { |
86 | 0 | pLibrary = dlopen(pszLibrary, RTLD_LAZY); |
87 | 0 | if (pLibrary == nullptr) |
88 | 0 | { |
89 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "%s", dlerror()); |
90 | 0 | return nullptr; |
91 | 0 | } |
92 | 0 | mapLibraryNameToHandle[pszNonNullLibrary] = pLibrary; |
93 | 0 | } |
94 | 0 | else |
95 | 0 | { |
96 | 0 | pLibrary = oIter->second; |
97 | 0 | } |
98 | | |
99 | 0 | 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 | 0 | if (pSymbol == nullptr) |
115 | 0 | { |
116 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "%s", dlerror()); |
117 | 0 | return nullptr; |
118 | 0 | } |
119 | | |
120 | 0 | return (pSymbol); |
121 | 0 | } |
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 |