(root)/
glib-2.79.0/
gmodule/
gmodule-dl.c
       1  /* GMODULE - GLIB wrapper code for dynamic module loading
       2   * Copyright (C) 1998, 2000 Tim Janik
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   */
      19  
      20  /*
      21   * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22   * file for a list of people on the GLib Team.  See the ChangeLog
      23   * files for a list of changes.  These files are distributed with
      24   * GLib at ftp://ftp.gtk.org/pub/gtk/. 
      25   */
      26  
      27  /* 
      28   * MT safe
      29   */
      30  #include "config.h"
      31  
      32  #include <dlfcn.h>
      33  #include <glib.h>
      34  
      35  /* Perl includes <nlist.h> and <link.h> instead of <dlfcn.h> on some systems? */
      36  
      37  
      38  /* dlerror() is not implemented on all systems
      39   */
      40  #ifndef	G_MODULE_HAVE_DLERROR
      41  #  ifdef __NetBSD__
      42  #    define dlerror()	g_strerror (errno)
      43  #  else /* !__NetBSD__ */
      44  /* could we rely on errno's state here? */
      45  #    define dlerror()	"unknown dl-error"
      46  #  endif /* !__NetBSD__ */
      47  #endif	/* G_MODULE_HAVE_DLERROR */
      48  
      49  /* some flags are missing on some systems, so we provide
      50   * harmless defaults.
      51   * The Perl sources say, RTLD_LAZY needs to be defined as (1),
      52   * at least for Solaris 1.
      53   *
      54   * Mandatory:
      55   * RTLD_LAZY   - resolve undefined symbols as code from the dynamic library
      56   *		 is executed.
      57   * RTLD_NOW    - resolve all undefined symbols before dlopen returns, and fail
      58   *		 if this cannot be done.
      59   * Optionally:
      60   * RTLD_GLOBAL - the external symbols defined in the library will be made
      61   *		 available to subsequently loaded libraries.
      62   */
      63  #ifndef	HAVE_RTLD_LAZY
      64  #define	RTLD_LAZY	1
      65  #endif	/* RTLD_LAZY */
      66  #ifndef	HAVE_RTLD_NOW
      67  #define	RTLD_NOW	0
      68  #endif	/* RTLD_NOW */
      69  /* some systems (OSF1 V5.0) have broken RTLD_GLOBAL linkage */
      70  #ifdef G_MODULE_BROKEN_RTLD_GLOBAL
      71  #undef	RTLD_GLOBAL
      72  #undef	HAVE_RTLD_GLOBAL
      73  #endif /* G_MODULE_BROKEN_RTLD_GLOBAL */
      74  #ifndef	HAVE_RTLD_GLOBAL
      75  #define	RTLD_GLOBAL	0
      76  #endif	/* RTLD_GLOBAL */
      77  
      78  
      79  /* According to POSIX.1-2001, dlerror() is not necessarily thread-safe
      80   * (see https://pubs.opengroup.org/onlinepubs/009695399/), and so must be
      81   * called within the same locked section as the dlopen()/dlsym() call which
      82   * may have caused an error.
      83   *
      84   * However, some libc implementations, such as glibc, implement dlerror() using
      85   * thread-local storage, so are thread-safe. As of early 2021:
      86   *  - glibc is thread-safe: https://github.com/bminor/glibc/blob/HEAD/dlfcn/libc_dlerror_result.c
      87   *  - uclibc-ng is not thread-safe: https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/ldso/libdl/libdl.c?id=132decd2a043d0ccf799f42bf89f3ae0c11e95d5#n1075
      88   *  - Other libc implementations have not been checked, and no problems have
      89   *    been reported with them in 10 years, so default to assuming that they
      90   *    don’t need additional thread-safety from GLib
      91   */
      92  #if defined(__UCLIBC__)
      93  G_LOCK_DEFINE_STATIC (errors);
      94  #else
      95  #define DLERROR_IS_THREADSAFE 1
      96  #endif
      97  
      98  static void
      99  lock_dlerror (void)
     100  {
     101  #ifndef DLERROR_IS_THREADSAFE
     102    G_LOCK (errors);
     103  #endif
     104  }
     105  
     106  static void
     107  unlock_dlerror (void)
     108  {
     109  #ifndef DLERROR_IS_THREADSAFE
     110    G_UNLOCK (errors);
     111  #endif
     112  }
     113  
     114  /* This should be called with lock_dlerror() held */
     115  static const gchar *
     116  fetch_dlerror (gboolean replace_null)
     117  {
     118    const gchar *msg = dlerror ();
     119  
     120    /* make sure we always return an error message != NULL, if
     121     * expected to do so. */
     122  
     123    if (!msg && replace_null)
     124      return "unknown dl-error";
     125  
     126    return msg;
     127  }
     128  
     129  static gpointer
     130  _g_module_open (const gchar *file_name,
     131  		gboolean     bind_lazy,
     132  		gboolean     bind_local,
     133                  GError     **error)
     134  {
     135    gpointer handle;
     136    
     137    lock_dlerror ();
     138    handle = dlopen (file_name,
     139  		   (bind_local ? 0 : RTLD_GLOBAL) | (bind_lazy ? RTLD_LAZY : RTLD_NOW));
     140    if (!handle)
     141      {
     142        const gchar *message = fetch_dlerror (TRUE);
     143  
     144        g_module_set_error (message);
     145        g_set_error_literal (error, G_MODULE_ERROR, G_MODULE_ERROR_FAILED, message);
     146      }
     147  
     148    unlock_dlerror ();
     149    
     150    return handle;
     151  }
     152  
     153  static gpointer
     154  _g_module_self (void)
     155  {
     156    gpointer handle;
     157    
     158    /* to query symbols from the program itself, special link options
     159     * are required on some systems.
     160     */
     161  
     162    /* On Android 32 bit (i.e. not __LP64__), dlopen(NULL)
     163     * does not work reliable and generally no symbols are found
     164     * at all. RTLD_DEFAULT works though.
     165     * On Android 64 bit, dlopen(NULL) seems to work but dlsym(handle)
     166     * always returns 'undefined symbol'. Only if RTLD_DEFAULT or 
     167     * NULL is given, dlsym returns an appropriate pointer.
     168     */
     169    lock_dlerror ();
     170  #if defined(__BIONIC__) || defined(__NetBSD__) || defined(__FreeBSD__)
     171    handle = RTLD_DEFAULT;
     172  #else
     173    handle = dlopen (NULL, RTLD_GLOBAL | RTLD_LAZY);
     174  #endif
     175    if (!handle)
     176      g_module_set_error (fetch_dlerror (TRUE));
     177    unlock_dlerror ();
     178    
     179    return handle;
     180  }
     181  
     182  static void
     183  _g_module_close (gpointer handle)
     184  {
     185  #if defined(__BIONIC__) || defined(__NetBSD__) || defined(__FreeBSD__)
     186    if (handle != RTLD_DEFAULT)
     187  #endif
     188      {
     189        lock_dlerror ();
     190        if (dlclose (handle) != 0)
     191          g_module_set_error (fetch_dlerror (TRUE));
     192        unlock_dlerror ();
     193      }
     194  }
     195  
     196  static gpointer
     197  _g_module_symbol (gpointer     handle,
     198  		  const gchar *symbol_name)
     199  {
     200    gpointer p;
     201    const gchar *msg;
     202  
     203    lock_dlerror ();
     204    fetch_dlerror (FALSE);
     205    p = dlsym (handle, symbol_name);
     206    msg = fetch_dlerror (FALSE);
     207    if (msg)
     208      g_module_set_error (msg);
     209    unlock_dlerror ();
     210    
     211    return p;
     212  }