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