/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 | | /************************************************************************/ |
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 | | void *CPLGetSymbol(const char *pszLibrary, const char *pszSymbolName) |
72 | | |
73 | 0 | { |
74 | 0 | void *pLibrary = dlopen(pszLibrary, RTLD_LAZY); |
75 | 0 | if (pLibrary == nullptr) |
76 | 0 | { |
77 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "%s", dlerror()); |
78 | 0 | return nullptr; |
79 | 0 | } |
80 | | |
81 | 0 | 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 | 0 | if (pSymbol == nullptr) |
97 | 0 | { |
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 | 0 | } |
103 | | |
104 | | // coverity[leaked_storage] It is not safe to call dlclose. |
105 | 0 | return (pSymbol); |
106 | 0 | } |
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 |