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 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_port.h"
31 #include "cpl_conv.h"
32
33 #include <cstddef>
34
35 #include "cpl_config.h"
36 #include "cpl_error.h"
37 #include "cpl_string.h"
38
39 CPL_CVSID("$Id: cplgetsymbol.cpp b1c9c12ad373e40b955162b45d704070d4ebf7b0 2019-06-19 16:50:15 +0200 Even Rouault $")
40
41 /* ==================================================================== */
42 /* Unix Implementation */
43 /* ==================================================================== */
44
45 /* MinGW32 might define HAVE_DLFCN_H, so skip the unix implementation */
46 #if defined(HAVE_DLFCN_H) && !defined(WIN32)
47
48 #define GOT_GETSYMBOL
49
50 #include <dlfcn.h>
51
52 /************************************************************************/
53 /* CPLGetSymbol() */
54 /************************************************************************/
55
56 /**
57 * Fetch a function pointer from a shared library / DLL.
58 *
59 * This function is meant to abstract access to shared libraries and
60 * DLLs and performs functions similar to dlopen()/dlsym() on Unix and
61 * LoadLibrary() / GetProcAddress() on Windows.
62 *
63 * If no support for loading entry points from a shared library is available
64 * this function will always return NULL. Rules on when this function
65 * issues a CPLError() or not are not currently well defined, and will have
66 * to be resolved in the future.
67 *
68 * Currently CPLGetSymbol() doesn't try to:
69 * <ul>
70 * <li> prevent the reference count on the library from going up
71 * for every request, or given any opportunity to unload
72 * the library.
73 * <li> Attempt to look for the library in non-standard
74 * locations.
75 * <li> Attempt to try variations on the symbol name, like
76 * pre-pending or post-pending an underscore.
77 * </ul>
78 *
79 * Some of these issues may be worked on in the future.
80 *
81 * @param pszLibrary the name of the shared library or DLL containing
82 * the function. May contain path to file. If not system supplies search
83 * paths will be used.
84 * @param pszSymbolName the name of the function to fetch a pointer to.
85 * @return A pointer to the function if found, or NULL if the function isn't
86 * found, or the shared library can't be loaded.
87 */
88
CPLGetSymbol(const char * pszLibrary,const char * pszSymbolName)89 void *CPLGetSymbol( const char * pszLibrary, const char * pszSymbolName )
90
91 {
92 void *pLibrary = dlopen(pszLibrary, RTLD_LAZY);
93 if( pLibrary == nullptr )
94 {
95 CPLError( CE_Failure, CPLE_AppDefined,
96 "%s", dlerror() );
97 return nullptr;
98 }
99
100 void *pSymbol = dlsym( pLibrary, pszSymbolName );
101
102 #if (defined(__APPLE__) && defined(__MACH__))
103 /* On mach-o systems, C symbols have a leading underscore and depending
104 * on how dlcompat is configured it may or may not add the leading
105 * underscore. If dlsym() fails, add an underscore and try again.
106 */
107 if( pSymbol == nullptr )
108 {
109 char withUnder[256] = {};
110 snprintf(withUnder, sizeof(withUnder), "_%s", pszSymbolName);
111 pSymbol = dlsym( pLibrary, withUnder );
112 }
113 #endif
114
115 if( pSymbol == nullptr )
116 {
117 CPLError( CE_Failure, CPLE_AppDefined,
118 "%s", dlerror() );
119 // Do not call dlclose here. misc.py:misc_6() demonstrates the crash.
120 // coverity[leaked_storage]
121 return nullptr;
122 }
123
124 // coverity[leaked_storage] It is not safe to call dlclose.
125 return( pSymbol );
126 }
127
128 #endif /* def __unix__ && defined(HAVE_DLFCN_H) */
129
130 /* ==================================================================== */
131 /* Windows Implementation */
132 /* ==================================================================== */
133 #if defined(WIN32)
134
135 #define GOT_GETSYMBOL
136
137 #include <windows.h>
138
139 /************************************************************************/
140 /* CPLGetSymbol() */
141 /************************************************************************/
142
CPLGetSymbol(const char * pszLibrary,const char * pszSymbolName)143 void *CPLGetSymbol( const char * pszLibrary, const char * pszSymbolName )
144
145 {
146 void *pLibrary = nullptr;
147 void *pSymbol = nullptr;
148
149 // Avoid error boxes to pop up (#5211, #5525).
150 UINT uOldErrorMode =
151 SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
152
153 #if defined(_MSC_VER) || __MSVCRT_VERSION__ >= 0x0601
154 if( CPLTestBool( CPLGetConfigOption( "GDAL_FILENAME_IS_UTF8", "YES" ) ) )
155 {
156 wchar_t *pwszFilename =
157 CPLRecodeToWChar( pszLibrary, CPL_ENC_UTF8, CPL_ENC_UCS2 );
158 pLibrary = LoadLibraryW(pwszFilename);
159 CPLFree( pwszFilename );
160 }
161 else
162 #endif
163 {
164 pLibrary = LoadLibraryA(pszLibrary);
165 }
166
167 if( pLibrary <= (void*)HINSTANCE_ERROR )
168 {
169 LPVOID lpMsgBuf = nullptr;
170 int nLastError = GetLastError();
171
172 // Restore old error mode.
173 SetErrorMode(uOldErrorMode);
174
175 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
176 | FORMAT_MESSAGE_FROM_SYSTEM
177 | FORMAT_MESSAGE_IGNORE_INSERTS,
178 nullptr, nLastError,
179 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
180 reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr );
181
182 CPLError( CE_Failure, CPLE_AppDefined,
183 "Can't load requested DLL: %s\n%d: %s",
184 pszLibrary, nLastError, static_cast<const char *>(lpMsgBuf) );
185 return nullptr;
186 }
187
188 // Restore old error mode.
189 SetErrorMode(uOldErrorMode);
190
191 pSymbol = reinterpret_cast<void *>(GetProcAddress( static_cast<HINSTANCE>(pLibrary), pszSymbolName ));
192
193 if( pSymbol == nullptr )
194 {
195 CPLError( CE_Failure, CPLE_AppDefined,
196 "Can't find requested entry point: %s", pszSymbolName );
197 return nullptr;
198 }
199
200 return( pSymbol );
201 }
202
203 #endif // def _WIN32
204
205 /* ==================================================================== */
206 /* Dummy implementation. */
207 /* ==================================================================== */
208
209 #ifndef GOT_GETSYMBOL
210
211 /************************************************************************/
212 /* CPLGetSymbol() */
213 /* */
214 /* Dummy implementation. */
215 /************************************************************************/
216
CPLGetSymbol(const char * pszLibrary,const char * pszEntryPoint)217 void *CPLGetSymbol(const char *pszLibrary, const char *pszEntryPoint)
218
219 {
220 CPLDebug( "CPL",
221 "CPLGetSymbol(%s,%s) called. Failed as this is stub"
222 " implementation.", pszLibrary, pszEntryPoint );
223 return nullptr;
224 }
225 #endif
226