LCOV - code coverage report
Current view: top level - port - cplgetsymbol.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 12 17 70.6 %
Date: 2025-07-03 09:54:33 Functions: 1 1 100.0 %

          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

Generated by: LCOV version 1.14