Blame elf/dl-close.c

Packit Service 82fcde
/* Close a shared object opened by `_dl_open'.
Packit Service 82fcde
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <dlfcn.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <libintl.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <libc-lock.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
#include <sys/mman.h>
Packit Service 82fcde
#include <sysdep-cancel.h>
Packit Service 82fcde
#include <tls.h>
Packit Service 82fcde
#include <stap-probe.h>
Packit Service 82fcde
Packit Service 82fcde
#include <dl-unmap-segments.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Type of the constructor functions.  */
Packit Service 82fcde
typedef void (*fini_t) (void);
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Special l_idx value used to indicate which objects remain loaded.  */
Packit Service 82fcde
#define IDX_STILL_USED -1
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Returns true we an non-empty was found.  */
Packit Service 82fcde
static bool
Packit Service 82fcde
remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
Packit Service 82fcde
		 bool should_be_there)
Packit Service 82fcde
{
Packit Service 82fcde
  if (idx - disp >= listp->len)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (listp->next == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* The index is not actually valid in the slotinfo list,
Packit Service 82fcde
	     because this object was closed before it was fully set
Packit Service 82fcde
	     up due to some error.  */
Packit Service 82fcde
	  assert (! should_be_there);
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (remove_slotinfo (idx, listp->next, disp + listp->len,
Packit Service 82fcde
			       should_be_there))
Packit Service 82fcde
	    return true;
Packit Service 82fcde
Packit Service 82fcde
	  /* No non-empty entry.  Search from the end of this element's
Packit Service 82fcde
	     slotinfo array.  */
Packit Service 82fcde
	  idx = disp + listp->len;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      struct link_map *old_map = listp->slotinfo[idx - disp].map;
Packit Service 82fcde
Packit Service 82fcde
      /* The entry might still be in its unused state if we are closing an
Packit Service 82fcde
	 object that wasn't fully set up.  */
Packit Service 82fcde
      if (__glibc_likely (old_map != NULL))
Packit Service 82fcde
	{
Packit Service 82fcde
	  assert (old_map->l_tls_modid == idx);
Packit Service 82fcde
Packit Service 82fcde
	  /* Mark the entry as unused. */
Packit Service 82fcde
	  listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1;
Packit Service 82fcde
	  listp->slotinfo[idx - disp].map = NULL;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* If this is not the last currently used entry no need to look
Packit Service 82fcde
	 further.  */
Packit Service 82fcde
      if (idx != GL(dl_tls_max_dtv_idx))
Packit Service 82fcde
	return true;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
Packit Service 82fcde
    {
Packit Service 82fcde
      --idx;
Packit Service 82fcde
Packit Service 82fcde
      if (listp->slotinfo[idx - disp].map != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Found a new last used index.  */
Packit Service 82fcde
	  GL(dl_tls_max_dtv_idx) = idx;
Packit Service 82fcde
	  return true;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* No non-entry in this list element.  */
Packit Service 82fcde
  return false;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_close_worker (struct link_map *map, bool force)
Packit Service 82fcde
{
Packit Service 82fcde
  /* One less direct use.  */
Packit Service 82fcde
  --map->l_direct_opencount;
Packit Service 82fcde
Packit Service 82fcde
  /* If _dl_close is called recursively (some destructor call dlclose),
Packit Service 82fcde
     just record that the parent _dl_close will need to do garbage collection
Packit Service 82fcde
     again and return.  */
Packit Service 82fcde
  static enum { not_pending, pending, rerun } dl_close_state;
Packit Service 82fcde
Packit Service 82fcde
  if (map->l_direct_opencount > 0 || map->l_type != lt_loaded
Packit Service 82fcde
      || dl_close_state != not_pending)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (map->l_direct_opencount == 0 && map->l_type == lt_loaded)
Packit Service 82fcde
	dl_close_state = rerun;
Packit Service 82fcde
Packit Service 82fcde
      /* There are still references to this object.  Do nothing more.  */
Packit Service 82fcde
      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
Packit Service 82fcde
	_dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n",
Packit Service 82fcde
			  map->l_name, map->l_direct_opencount);
Packit Service 82fcde
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  Lmid_t nsid = map->l_ns;
Packit Service 82fcde
  struct link_namespaces *ns = &GL(dl_ns)[nsid];
Packit Service 82fcde
Packit Service 82fcde
 retry:
Packit Service 82fcde
  dl_close_state = pending;
Packit Service 82fcde
Packit Service 82fcde
  bool any_tls = false;
Packit Service 82fcde
  const unsigned int nloaded = ns->_ns_nloaded;
Packit Service 82fcde
  char used[nloaded];
Packit Service 82fcde
  char done[nloaded];
Packit Service 82fcde
  struct link_map *maps[nloaded];
Packit Service 82fcde
Packit Service 1c5418
  /* Clear DF_1_NODELETE to force object deletion.  We don't need to touch
Packit Service 1c5418
     l_tls_dtor_count because forced object deletion only happens when an
Packit Service 1c5418
     error occurs during object load.  Destructor registration for TLS
Packit Service 1c5418
     non-POD objects should not have happened till then for this
Packit Service 1c5418
     object.  */
Packit Service 1c5418
  if (force)
Packit Service 1c5418
    map->l_flags_1 &= ~DF_1_NODELETE;
Packit Service 1c5418
Packit Service 82fcde
  /* Run over the list and assign indexes to the link maps and enter
Packit Service 82fcde
     them into the MAPS array.  */
Packit Service 82fcde
  int idx = 0;
Packit Service 82fcde
  for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next)
Packit Service 82fcde
    {
Packit Service 82fcde
      l->l_idx = idx;
Packit Service 82fcde
      maps[idx] = l;
Packit Service 82fcde
      ++idx;
Packit Service 82fcde
Packit Service 82fcde
    }
Packit Service 82fcde
  assert (idx == nloaded);
Packit Service 82fcde
Packit Service 82fcde
  /* Prepare the bitmaps.  */
Packit Service 82fcde
  memset (used, '\0', sizeof (used));
Packit Service 82fcde
  memset (done, '\0', sizeof (done));
Packit Service 82fcde
Packit Service 82fcde
  /* Keep track of the lowest index link map we have covered already.  */
Packit Service 82fcde
  int done_index = -1;
Packit Service 82fcde
  while (++done_index < nloaded)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct link_map *l = maps[done_index];
Packit Service 82fcde
Packit Service 82fcde
      if (done[done_index])
Packit Service 82fcde
	/* Already handled.  */
Packit Service 82fcde
	continue;
Packit Service 82fcde
Packit Service 82fcde
      /* Check whether this object is still used.  */
Packit Service 82fcde
      if (l->l_type == lt_loaded
Packit Service 82fcde
	  && l->l_direct_opencount == 0
Packit Service 1c5418
	  && (l->l_flags_1 & DF_1_NODELETE) == 0
Packit Service 82fcde
	  /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
Packit Service 82fcde
	     acquire is sufficient and correct.  */
Packit Service 82fcde
	  && atomic_load_acquire (&l->l_tls_dtor_count) == 0
Packit Service 82fcde
	  && !used[done_index])
Packit Service 82fcde
	continue;
Packit Service 82fcde
Packit Service 82fcde
      /* We need this object and we handle it now.  */
Packit Service 82fcde
      done[done_index] = 1;
Packit Service 82fcde
      used[done_index] = 1;
Packit Service 82fcde
      /* Signal the object is still needed.  */
Packit Service 82fcde
      l->l_idx = IDX_STILL_USED;
Packit Service 82fcde
Packit Service 82fcde
      /* Mark all dependencies as used.  */
Packit Service 82fcde
      if (l->l_initfini != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We are always the zeroth entry, and since we don't include
Packit Service 82fcde
	     ourselves in the dependency analysis start at 1.  */
Packit Service 82fcde
	  struct link_map **lp = &l->l_initfini[1];
Packit Service 82fcde
	  while (*lp != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if ((*lp)->l_idx != IDX_STILL_USED)
Packit Service 82fcde
		{
Packit Service 82fcde
		  assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
Packit Service 82fcde
Packit Service 82fcde
		  if (!used[(*lp)->l_idx])
Packit Service 82fcde
		    {
Packit Service 82fcde
		      used[(*lp)->l_idx] = 1;
Packit Service 82fcde
		      /* If we marked a new object as used, and we've
Packit Service 82fcde
			 already processed it, then we need to go back
Packit Service 82fcde
			 and process again from that point forward to
Packit Service 82fcde
			 ensure we keep all of its dependencies also.  */
Packit Service 82fcde
		      if ((*lp)->l_idx - 1 < done_index)
Packit Service 82fcde
			done_index = (*lp)->l_idx - 1;
Packit Service 82fcde
		    }
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      ++lp;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
      /* And the same for relocation dependencies.  */
Packit Service 82fcde
      if (l->l_reldeps != NULL)
Packit Service 82fcde
	for (unsigned int j = 0; j < l->l_reldeps->act; ++j)
Packit Service 82fcde
	  {
Packit Service 82fcde
	    struct link_map *jmap = l->l_reldeps->list[j];
Packit Service 82fcde
Packit Service 82fcde
	    if (jmap->l_idx != IDX_STILL_USED)
Packit Service 82fcde
	      {
Packit Service 82fcde
		assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
Packit Service 82fcde
Packit Service 82fcde
		if (!used[jmap->l_idx])
Packit Service 82fcde
		  {
Packit Service 82fcde
		    used[jmap->l_idx] = 1;
Packit Service 82fcde
		    if (jmap->l_idx - 1 < done_index)
Packit Service 82fcde
		      done_index = jmap->l_idx - 1;
Packit Service 82fcde
		  }
Packit Service 82fcde
	      }
Packit Service 82fcde
	  }
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Sort the entries.  We can skip looking for the binary itself which is
Packit Service 82fcde
     at the front of the search list for the main namespace.  */
Packit Service 82fcde
  _dl_sort_maps (maps + (nsid == LM_ID_BASE), nloaded - (nsid == LM_ID_BASE),
Packit Service 82fcde
		 used + (nsid == LM_ID_BASE), true);
Packit Service 82fcde
Packit Service 82fcde
  /* Call all termination functions at once.  */
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  bool do_audit = GLRO(dl_naudit) > 0 && !ns->_ns_loaded->l_auditing;
Packit Service 82fcde
#endif
Packit Service 82fcde
  bool unload_any = false;
Packit Service 82fcde
  bool scope_mem_left = false;
Packit Service 82fcde
  unsigned int unload_global = 0;
Packit Service 82fcde
  unsigned int first_loaded = ~0;
Packit Service 82fcde
  for (unsigned int i = 0; i < nloaded; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct link_map *imap = maps[i];
Packit Service 82fcde
Packit Service 82fcde
      /* All elements must be in the same namespace.  */
Packit Service 82fcde
      assert (imap->l_ns == nsid);
Packit Service 82fcde
Packit Service 82fcde
      if (!used[i])
Packit Service 82fcde
	{
Packit Service 1c5418
	  assert (imap->l_type == lt_loaded
Packit Service 1c5418
		  && (imap->l_flags_1 & DF_1_NODELETE) == 0);
Packit Service 82fcde
Packit Service 82fcde
	  /* Call its termination function.  Do not do it for
Packit Service 1c5418
	     half-cooked objects.  */
Packit Service 82fcde
	  if (imap->l_init_called)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* When debugging print a message first.  */
Packit Service 82fcde
	      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
Packit Service 82fcde
				    0))
Packit Service 82fcde
		_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
Packit Service 82fcde
				  imap->l_name, nsid);
Packit Service 82fcde
Packit Service 1c5418
	      if (imap->l_info[DT_FINI_ARRAY] != NULL)
Packit Service 1c5418
		{
Packit Service 1c5418
		  ElfW(Addr) *array =
Packit Service 1c5418
		    (ElfW(Addr) *) (imap->l_addr
Packit Service 1c5418
				    + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
Packit Service 1c5418
		  unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
Packit Service 1c5418
				     / sizeof (ElfW(Addr)));
Packit Service 1c5418
Packit Service 1c5418
		  while (sz-- > 0)
Packit Service 1c5418
		    ((fini_t) array[sz]) ();
Packit Service 1c5418
		}
Packit Service 1c5418
Packit Service 1c5418
	      /* Next try the old-style destructor.  */
Packit Service 1c5418
	      if (imap->l_info[DT_FINI] != NULL)
Packit Service 1c5418
		DL_CALL_DT_FINI (imap, ((void *) imap->l_addr
Packit Service 1c5418
			 + imap->l_info[DT_FINI]->d_un.d_ptr));
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
	  /* Auditing checkpoint: we remove an object.  */
Packit Service 82fcde
	  if (__glibc_unlikely (do_audit))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      struct audit_ifaces *afct = GLRO(dl_audit);
Packit Service 82fcde
	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit Service 82fcde
		{
Packit Service 82fcde
		  if (afct->objclose != NULL)
Packit Service 82fcde
		    /* Return value is ignored.  */
Packit Service 82fcde
		    (void) afct->objclose (&imap->l_audit[cnt].cookie);
Packit Service 82fcde
Packit Service 82fcde
		  afct = afct->next;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
	  /* This object must not be used anymore.  */
Packit Service 82fcde
	  imap->l_removed = 1;
Packit Service 82fcde
Packit Service 82fcde
	  /* We indeed have an object to remove.  */
Packit Service 82fcde
	  unload_any = true;
Packit Service 82fcde
Packit Service 82fcde
	  if (imap->l_global)
Packit Service 82fcde
	    ++unload_global;
Packit Service 82fcde
Packit Service 82fcde
	  /* Remember where the first dynamically loaded object is.  */
Packit Service 82fcde
	  if (i < first_loaded)
Packit Service 82fcde
	    first_loaded = i;
Packit Service 82fcde
	}
Packit Service 82fcde
      /* Else used[i].  */
Packit Service 82fcde
      else if (imap->l_type == lt_loaded)
Packit Service 82fcde
	{
Packit Service 82fcde
	  struct r_scope_elem *new_list = NULL;
Packit Service 82fcde
Packit Service 82fcde
	  if (imap->l_searchlist.r_list == NULL && imap->l_initfini != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* The object is still used.  But one of the objects we are
Packit Service 82fcde
		 unloading right now is responsible for loading it.  If
Packit Service 82fcde
		 the current object does not have it's own scope yet we
Packit Service 82fcde
		 have to create one.  This has to be done before running
Packit Service 82fcde
		 the finalizers.
Packit Service 82fcde
Packit Service 82fcde
		 To do this count the number of dependencies.  */
Packit Service 82fcde
	      unsigned int cnt;
Packit Service 82fcde
	      for (cnt = 1; imap->l_initfini[cnt] != NULL; ++cnt)
Packit Service 82fcde
		;
Packit Service 82fcde
Packit Service 82fcde
	      /* We simply reuse the l_initfini list.  */
Packit Service 82fcde
	      imap->l_searchlist.r_list = &imap->l_initfini[cnt + 1];
Packit Service 82fcde
	      imap->l_searchlist.r_nlist = cnt;
Packit Service 82fcde
Packit Service 82fcde
	      new_list = &imap->l_searchlist;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Count the number of scopes which remain after the unload.
Packit Service 82fcde
	     When we add the local search list count it.  Always add
Packit Service 82fcde
	     one for the terminating NULL pointer.  */
Packit Service 82fcde
	  size_t remain = (new_list != NULL) + 1;
Packit Service 82fcde
	  bool removed_any = false;
Packit Service 82fcde
	  for (size_t cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
Packit Service 82fcde
	    /* This relies on l_scope[] entries being always set either
Packit Service 82fcde
	       to its own l_symbolic_searchlist address, or some map's
Packit Service 82fcde
	       l_searchlist address.  */
Packit Service 82fcde
	    if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
Packit Service 82fcde
	      {
Packit Service 82fcde
		struct link_map *tmap = (struct link_map *)
Packit Service 82fcde
		  ((char *) imap->l_scope[cnt]
Packit Service 82fcde
		   - offsetof (struct link_map, l_searchlist));
Packit Service 82fcde
		assert (tmap->l_ns == nsid);
Packit Service 82fcde
		if (tmap->l_idx == IDX_STILL_USED)
Packit Service 82fcde
		  ++remain;
Packit Service 82fcde
		else
Packit Service 82fcde
		  removed_any = true;
Packit Service 82fcde
	      }
Packit Service 82fcde
	    else
Packit Service 82fcde
	      ++remain;
Packit Service 82fcde
Packit Service 82fcde
	  if (removed_any)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Always allocate a new array for the scope.  This is
Packit Service 82fcde
		 necessary since we must be able to determine the last
Packit Service 82fcde
		 user of the current array.  If possible use the link map's
Packit Service 82fcde
		 memory.  */
Packit Service 82fcde
	      size_t new_size;
Packit Service 82fcde
	      struct r_scope_elem **newp;
Packit Service 82fcde
Packit Service 82fcde
#define SCOPE_ELEMS(imap) \
Packit Service 82fcde
  (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0]))
Packit Service 82fcde
Packit Service 82fcde
	      if (imap->l_scope != imap->l_scope_mem
Packit Service 82fcde
		  && remain < SCOPE_ELEMS (imap))
Packit Service 82fcde
		{
Packit Service 82fcde
		  new_size = SCOPE_ELEMS (imap);
Packit Service 82fcde
		  newp = imap->l_scope_mem;
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		{
Packit Service 82fcde
		  new_size = imap->l_scope_max;
Packit Service 82fcde
		  newp = (struct r_scope_elem **)
Packit Service 82fcde
		    malloc (new_size * sizeof (struct r_scope_elem *));
Packit Service 82fcde
		  if (newp == NULL)
Packit Service 82fcde
		    _dl_signal_error (ENOMEM, "dlclose", NULL,
Packit Service 82fcde
				      N_("cannot create scope list"));
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      /* Copy over the remaining scope elements.  */
Packit Service 82fcde
	      remain = 0;
Packit Service 82fcde
	      for (size_t cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
Packit Service 82fcde
		{
Packit Service 82fcde
		  if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      struct link_map *tmap = (struct link_map *)
Packit Service 82fcde
			((char *) imap->l_scope[cnt]
Packit Service 82fcde
			 - offsetof (struct link_map, l_searchlist));
Packit Service 82fcde
		      if (tmap->l_idx != IDX_STILL_USED)
Packit Service 82fcde
			{
Packit Service 82fcde
			  /* Remove the scope.  Or replace with own map's
Packit Service 82fcde
			     scope.  */
Packit Service 82fcde
			  if (new_list != NULL)
Packit Service 82fcde
			    {
Packit Service 82fcde
			      newp[remain++] = new_list;
Packit Service 82fcde
			      new_list = NULL;
Packit Service 82fcde
			    }
Packit Service 82fcde
			  continue;
Packit Service 82fcde
			}
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
		  newp[remain++] = imap->l_scope[cnt];
Packit Service 82fcde
		}
Packit Service 82fcde
	      newp[remain] = NULL;
Packit Service 82fcde
Packit Service 82fcde
	      struct r_scope_elem **old = imap->l_scope;
Packit Service 82fcde
Packit Service 82fcde
	      imap->l_scope = newp;
Packit Service 82fcde
Packit Service 82fcde
	      /* No user anymore, we can free it now.  */
Packit Service 82fcde
	      if (old != imap->l_scope_mem)
Packit Service 82fcde
		{
Packit Service 82fcde
		  if (_dl_scope_free (old))
Packit Service 82fcde
		    /* If _dl_scope_free used THREAD_GSCOPE_WAIT (),
Packit Service 82fcde
		       no need to repeat it.  */
Packit Service 82fcde
		    scope_mem_left = false;
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		scope_mem_left = true;
Packit Service 82fcde
Packit Service 82fcde
	      imap->l_scope_max = new_size;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else if (new_list != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* We didn't change the scope array, so reset the search
Packit Service 82fcde
		 list.  */
Packit Service 82fcde
	      imap->l_searchlist.r_list = NULL;
Packit Service 82fcde
	      imap->l_searchlist.r_nlist = 0;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* The loader is gone, so mark the object as not having one.
Packit Service 82fcde
	     Note: l_idx != IDX_STILL_USED -> object will be removed.  */
Packit Service 82fcde
	  if (imap->l_loader != NULL
Packit Service 82fcde
	      && imap->l_loader->l_idx != IDX_STILL_USED)
Packit Service 82fcde
	    imap->l_loader = NULL;
Packit Service 82fcde
Packit Service 82fcde
	  /* Remember where the first dynamically loaded object is.  */
Packit Service 82fcde
	  if (i < first_loaded)
Packit Service 82fcde
	    first_loaded = i;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* If there are no objects to unload, do nothing further.  */
Packit Service 82fcde
  if (!unload_any)
Packit Service 82fcde
    goto out;
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  /* Auditing checkpoint: we will start deleting objects.  */
Packit Service 82fcde
  if (__glibc_unlikely (do_audit))
Packit Service 82fcde
    {
Packit Service 82fcde
      struct link_map *head = ns->_ns_loaded;
Packit Service 82fcde
      struct audit_ifaces *afct = GLRO(dl_audit);
Packit Service 82fcde
      /* Do not call the functions for any auditing object.  */
Packit Service 82fcde
      if (head->l_auditing == 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (afct->activity != NULL)
Packit Service 82fcde
		afct->activity (&head->l_audit[cnt].cookie, LA_ACT_DELETE);
Packit Service 82fcde
Packit Service 82fcde
	      afct = afct->next;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Notify the debugger we are about to remove some loaded objects.  */
Packit Service 82fcde
  struct r_debug *r = _dl_debug_initialize (0, nsid);
Packit Service 82fcde
  r->r_state = RT_DELETE;
Packit Service 82fcde
  _dl_debug_state ();
Packit Service 82fcde
  LIBC_PROBE (unmap_start, 2, nsid, r);
Packit Service 82fcde
Packit Service 82fcde
  if (unload_global)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Some objects are in the global scope list.  Remove them.  */
Packit Service 82fcde
      struct r_scope_elem *ns_msl = ns->_ns_main_searchlist;
Packit Service 82fcde
      unsigned int i;
Packit Service 82fcde
      unsigned int j = 0;
Packit Service 82fcde
      unsigned int cnt = ns_msl->r_nlist;
Packit Service 82fcde
Packit Service 82fcde
      while (cnt > 0 && ns_msl->r_list[cnt - 1]->l_removed)
Packit Service 82fcde
	--cnt;
Packit Service 82fcde
Packit Service 82fcde
      if (cnt + unload_global == ns_msl->r_nlist)
Packit Service 82fcde
	/* Speed up removing most recently added objects.  */
Packit Service 82fcde
	j = cnt;
Packit Service 82fcde
      else
Packit Service 82fcde
	for (i = 0; i < cnt; i++)
Packit Service 82fcde
	  if (ns_msl->r_list[i]->l_removed == 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (i != j)
Packit Service 82fcde
		ns_msl->r_list[j] = ns_msl->r_list[i];
Packit Service 82fcde
	      j++;
Packit Service 82fcde
	    }
Packit Service 82fcde
      ns_msl->r_nlist = j;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (!RTLD_SINGLE_THREAD_P
Packit Service 82fcde
      && (unload_global
Packit Service 82fcde
	  || scope_mem_left
Packit Service 82fcde
	  || (GL(dl_scope_free_list) != NULL
Packit Service 82fcde
	      && GL(dl_scope_free_list)->count)))
Packit Service 82fcde
    {
Packit Service 82fcde
      THREAD_GSCOPE_WAIT ();
Packit Service 82fcde
Packit Service 82fcde
      /* Now we can free any queued old scopes.  */
Packit Service 82fcde
      struct dl_scope_free_list *fsl = GL(dl_scope_free_list);
Packit Service 82fcde
      if (fsl != NULL)
Packit Service 82fcde
	while (fsl->count > 0)
Packit Service 82fcde
	  free (fsl->list[--fsl->count]);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  size_t tls_free_start;
Packit Service 82fcde
  size_t tls_free_end;
Packit Service 82fcde
  tls_free_start = tls_free_end = NO_TLS_OFFSET;
Packit Service 82fcde
Packit Service 82fcde
  /* We modify the list of loaded objects.  */
Packit Service 82fcde
  __rtld_lock_lock_recursive (GL(dl_load_write_lock));
Packit Service 82fcde
Packit Service 82fcde
  /* Check each element of the search list to see if all references to
Packit Service 82fcde
     it are gone.  */
Packit Service 82fcde
  for (unsigned int i = first_loaded; i < nloaded; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct link_map *imap = maps[i];
Packit Service 82fcde
      if (!used[i])
Packit Service 82fcde
	{
Packit Service 82fcde
	  assert (imap->l_type == lt_loaded);
Packit Service 82fcde
Packit Service 82fcde
	  /* That was the last reference, and this was a dlopen-loaded
Packit Service 82fcde
	     object.  We can unmap it.  */
Packit Service 82fcde
Packit Service 82fcde
	  /* Remove the object from the dtv slotinfo array if it uses TLS.  */
Packit Service 82fcde
	  if (__glibc_unlikely (imap->l_tls_blocksize > 0))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      any_tls = true;
Packit Service 82fcde
Packit Service 82fcde
	      if (GL(dl_tls_dtv_slotinfo_list) != NULL
Packit Service 82fcde
		  && ! remove_slotinfo (imap->l_tls_modid,
Packit Service 82fcde
					GL(dl_tls_dtv_slotinfo_list), 0,
Packit Service 82fcde
					imap->l_init_called))
Packit Service 82fcde
		/* All dynamically loaded modules with TLS are unloaded.  */
Packit Service 82fcde
		GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
Packit Service 82fcde
Packit Service 82fcde
	      if (imap->l_tls_offset != NO_TLS_OFFSET
Packit Service 82fcde
		  && imap->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Collect a contiguous chunk built from the objects in
Packit Service 82fcde
		     this search list, going in either direction.  When the
Packit Service 82fcde
		     whole chunk is at the end of the used area then we can
Packit Service 82fcde
		     reclaim it.  */
Packit Service 82fcde
#if TLS_TCB_AT_TP
Packit Service 82fcde
		  if (tls_free_start == NO_TLS_OFFSET
Packit Service 82fcde
		      || (size_t) imap->l_tls_offset == tls_free_start)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* Extend the contiguous chunk being reclaimed.  */
Packit Service 82fcde
		      tls_free_start
Packit Service 82fcde
			= imap->l_tls_offset - imap->l_tls_blocksize;
Packit Service 82fcde
Packit Service 82fcde
		      if (tls_free_end == NO_TLS_OFFSET)
Packit Service 82fcde
			tls_free_end = imap->l_tls_offset;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else if (imap->l_tls_offset - imap->l_tls_blocksize
Packit Service 82fcde
			   == tls_free_end)
Packit Service 82fcde
		    /* Extend the chunk backwards.  */
Packit Service 82fcde
		    tls_free_end = imap->l_tls_offset;
Packit Service 82fcde
		  else
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* This isn't contiguous with the last chunk freed.
Packit Service 82fcde
			 One of them will be leaked unless we can free
Packit Service 82fcde
			 one block right away.  */
Packit Service 82fcde
		      if (tls_free_end == GL(dl_tls_static_used))
Packit Service 82fcde
			{
Packit Service 82fcde
			  GL(dl_tls_static_used) = tls_free_start;
Packit Service 82fcde
			  tls_free_end = imap->l_tls_offset;
Packit Service 82fcde
			  tls_free_start
Packit Service 82fcde
			    = tls_free_end - imap->l_tls_blocksize;
Packit Service 82fcde
			}
Packit Service 82fcde
		      else if ((size_t) imap->l_tls_offset
Packit Service 82fcde
			       == GL(dl_tls_static_used))
Packit Service 82fcde
			GL(dl_tls_static_used)
Packit Service 82fcde
			  = imap->l_tls_offset - imap->l_tls_blocksize;
Packit Service 82fcde
		      else if (tls_free_end < (size_t) imap->l_tls_offset)
Packit Service 82fcde
			{
Packit Service 82fcde
			  /* We pick the later block.  It has a chance to
Packit Service 82fcde
			     be freed.  */
Packit Service 82fcde
			  tls_free_end = imap->l_tls_offset;
Packit Service 82fcde
			  tls_free_start
Packit Service 82fcde
			    = tls_free_end - imap->l_tls_blocksize;
Packit Service 82fcde
			}
Packit Service 82fcde
		    }
Packit Service 82fcde
#elif TLS_DTV_AT_TP
Packit Service 82fcde
		  if (tls_free_start == NO_TLS_OFFSET)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      tls_free_start = imap->l_tls_firstbyte_offset;
Packit Service 82fcde
		      tls_free_end = (imap->l_tls_offset
Packit Service 82fcde
				      + imap->l_tls_blocksize);
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else if (imap->l_tls_firstbyte_offset == tls_free_end)
Packit Service 82fcde
		    /* Extend the contiguous chunk being reclaimed.  */
Packit Service 82fcde
		    tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
Packit Service 82fcde
		  else if (imap->l_tls_offset + imap->l_tls_blocksize
Packit Service 82fcde
			   == tls_free_start)
Packit Service 82fcde
		    /* Extend the chunk backwards.  */
Packit Service 82fcde
		    tls_free_start = imap->l_tls_firstbyte_offset;
Packit Service 82fcde
		  /* This isn't contiguous with the last chunk freed.
Packit Service 82fcde
		     One of them will be leaked unless we can free
Packit Service 82fcde
		     one block right away.  */
Packit Service 82fcde
		  else if (imap->l_tls_offset + imap->l_tls_blocksize
Packit Service 82fcde
			   == GL(dl_tls_static_used))
Packit Service 82fcde
		    GL(dl_tls_static_used) = imap->l_tls_firstbyte_offset;
Packit Service 82fcde
		  else if (tls_free_end == GL(dl_tls_static_used))
Packit Service 82fcde
		    {
Packit Service 82fcde
		      GL(dl_tls_static_used) = tls_free_start;
Packit Service 82fcde
		      tls_free_start = imap->l_tls_firstbyte_offset;
Packit Service 82fcde
		      tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else if (tls_free_end < imap->l_tls_firstbyte_offset)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* We pick the later block.  It has a chance to
Packit Service 82fcde
			 be freed.  */
Packit Service 82fcde
		      tls_free_start = imap->l_tls_firstbyte_offset;
Packit Service 82fcde
		      tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
Packit Service 82fcde
		    }
Packit Service 82fcde
#else
Packit Service 82fcde
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
Packit Service 82fcde
#endif
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Reset unique symbols if forced.  */
Packit Service 82fcde
	  if (force)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      struct unique_sym_table *tab = &ns->_ns_unique_sym_table;
Packit Service 82fcde
	      __rtld_lock_lock_recursive (tab->lock);
Packit Service 82fcde
	      struct unique_sym *entries = tab->entries;
Packit Service 82fcde
	      if (entries != NULL)
Packit Service 82fcde
		{
Packit Service 82fcde
		  size_t idx, size = tab->size;
Packit Service 82fcde
		  for (idx = 0; idx < size; ++idx)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* Clear unique symbol entries that belong to this
Packit Service 82fcde
			 object.  */
Packit Service 82fcde
		      if (entries[idx].name != NULL
Packit Service 82fcde
			  && entries[idx].map == imap)
Packit Service 82fcde
			{
Packit Service 82fcde
			  entries[idx].name = NULL;
Packit Service 82fcde
			  entries[idx].hashval = 0;
Packit Service 82fcde
			  tab->n_elements--;
Packit Service 82fcde
			}
Packit Service 82fcde
		    }
Packit Service 82fcde
		}
Packit Service 82fcde
	      __rtld_lock_unlock_recursive (tab->lock);
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* We can unmap all the maps at once.  We determined the
Packit Service 82fcde
	     start address and length when we loaded the object and
Packit Service 82fcde
	     the `munmap' call does the rest.  */
Packit Service 82fcde
	  DL_UNMAP (imap);
Packit Service 82fcde
Packit Service 82fcde
	  /* Finally, unlink the data structure and free it.  */
Packit Service 82fcde
#if DL_NNS == 1
Packit Service 82fcde
	  /* The assert in the (imap->l_prev == NULL) case gives
Packit Service 82fcde
	     the compiler license to warn that NS points outside
Packit Service 82fcde
	     the dl_ns array bounds in that case (as nsid != LM_ID_BASE
Packit Service 82fcde
	     is tantamount to nsid >= DL_NNS).  That should be impossible
Packit Service 82fcde
	     in this configuration, so just assert about it instead.  */
Packit Service 82fcde
	  assert (nsid == LM_ID_BASE);
Packit Service 82fcde
	  assert (imap->l_prev != NULL);
Packit Service 82fcde
#else
Packit Service 82fcde
	  if (imap->l_prev == NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      assert (nsid != LM_ID_BASE);
Packit Service 82fcde
	      ns->_ns_loaded = imap->l_next;
Packit Service 82fcde
Packit Service 82fcde
	      /* Update the pointer to the head of the list
Packit Service 82fcde
		 we leave for debuggers to examine.  */
Packit Service 82fcde
	      r->r_map = (void *) ns->_ns_loaded;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
#endif
Packit Service 82fcde
	    imap->l_prev->l_next = imap->l_next;
Packit Service 82fcde
Packit Service 82fcde
	  --ns->_ns_nloaded;
Packit Service 82fcde
	  if (imap->l_next != NULL)
Packit Service 82fcde
	    imap->l_next->l_prev = imap->l_prev;
Packit Service 82fcde
Packit Service 82fcde
	  free (imap->l_versions);
Packit Service 82fcde
	  if (imap->l_origin != (char *) -1)
Packit Service 82fcde
	    free ((char *) imap->l_origin);
Packit Service 82fcde
Packit Service 82fcde
	  free (imap->l_reldeps);
Packit Service 82fcde
Packit Service 82fcde
	  /* Print debugging message.  */
Packit Service 82fcde
	  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
Packit Service 82fcde
	    _dl_debug_printf ("\nfile=%s [%lu];  destroying link map\n",
Packit Service 82fcde
			      imap->l_name, imap->l_ns);
Packit Service 82fcde
Packit Service 82fcde
	  /* This name always is allocated.  */
Packit Service 82fcde
	  free (imap->l_name);
Packit Service 82fcde
	  /* Remove the list with all the names of the shared object.  */
Packit Service 82fcde
Packit Service 82fcde
	  struct libname_list *lnp = imap->l_libname;
Packit Service 82fcde
	  do
Packit Service 82fcde
	    {
Packit Service 82fcde
	      struct libname_list *this = lnp;
Packit Service 82fcde
	      lnp = lnp->next;
Packit Service 82fcde
	      if (!this->dont_free)
Packit Service 82fcde
		free (this);
Packit Service 82fcde
	    }
Packit Service 82fcde
	  while (lnp != NULL);
Packit Service 82fcde
Packit Service 82fcde
	  /* Remove the searchlists.  */
Packit Service 82fcde
	  free (imap->l_initfini);
Packit Service 82fcde
Packit Service 82fcde
	  /* Remove the scope array if we allocated it.  */
Packit Service 82fcde
	  if (imap->l_scope != imap->l_scope_mem)
Packit Service 82fcde
	    free (imap->l_scope);
Packit Service 82fcde
Packit Service 82fcde
	  if (imap->l_phdr_allocated)
Packit Service 82fcde
	    free ((void *) imap->l_phdr);
Packit Service 82fcde
Packit Service 82fcde
	  if (imap->l_rpath_dirs.dirs != (void *) -1)
Packit Service 82fcde
	    free (imap->l_rpath_dirs.dirs);
Packit Service 82fcde
	  if (imap->l_runpath_dirs.dirs != (void *) -1)
Packit Service 82fcde
	    free (imap->l_runpath_dirs.dirs);
Packit Service 82fcde
Packit Service 82fcde
	  free (imap);
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
Packit Service 82fcde
Packit Service 82fcde
  /* If we removed any object which uses TLS bump the generation counter.  */
Packit Service 82fcde
  if (any_tls)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__glibc_unlikely (++GL(dl_tls_generation) == 0))
Packit Service 82fcde
	_dl_fatal_printf ("TLS generation counter wrapped!  Please report as described in "REPORT_BUGS_TO".\n");
Packit Service 82fcde
Packit Service 82fcde
      if (tls_free_end == GL(dl_tls_static_used))
Packit Service 82fcde
	GL(dl_tls_static_used) = tls_free_start;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  /* Auditing checkpoint: we have deleted all objects.  */
Packit Service 82fcde
  if (__glibc_unlikely (do_audit))
Packit Service 82fcde
    {
Packit Service 82fcde
      struct link_map *head = ns->_ns_loaded;
Packit Service 82fcde
      /* Do not call the functions for any auditing object.  */
Packit Service 82fcde
      if (head->l_auditing == 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  struct audit_ifaces *afct = GLRO(dl_audit);
Packit Service 82fcde
	  for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (afct->activity != NULL)
Packit Service 82fcde
		afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
Packit Service 82fcde
Packit Service 82fcde
	      afct = afct->next;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  if (__builtin_expect (ns->_ns_loaded == NULL, 0)
Packit Service 82fcde
      && nsid == GL(dl_nns) - 1)
Packit Service 82fcde
    do
Packit Service 82fcde
      --GL(dl_nns);
Packit Service 82fcde
    while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
Packit Service 82fcde
Packit Service 82fcde
  /* Notify the debugger those objects are finalized and gone.  */
Packit Service 82fcde
  r->r_state = RT_CONSISTENT;
Packit Service 82fcde
  _dl_debug_state ();
Packit Service 82fcde
  LIBC_PROBE (unmap_complete, 2, nsid, r);
Packit Service 82fcde
Packit Service 82fcde
  /* Recheck if we need to retry, release the lock.  */
Packit Service 82fcde
 out:
Packit Service 82fcde
  if (dl_close_state == rerun)
Packit Service 82fcde
    goto retry;
Packit Service 82fcde
Packit Service 82fcde
  dl_close_state = not_pending;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_close (void *_map)
Packit Service 82fcde
{
Packit Service 82fcde
  struct link_map *map = _map;
Packit Service 82fcde
Packit Service 82fcde
  /* We must take the lock to examine the contents of map and avoid
Packit Service 82fcde
     concurrent dlopens.  */
Packit Service 82fcde
  __rtld_lock_lock_recursive (GL(dl_load_lock));
Packit Service 82fcde
Packit Service 82fcde
  /* At this point we are guaranteed nobody else is touching the list of
Packit Service 82fcde
     loaded maps, but a concurrent dlclose might have freed our map
Packit Service 82fcde
     before we took the lock. There is no way to detect this (see below)
Packit Service 82fcde
     so we proceed assuming this isn't the case.  First see whether we
Packit Service 82fcde
     can remove the object at all.  */
Packit Service 1c5418
  if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Nope.  Do nothing.  */
Packit Service 82fcde
      __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* At present this is an unreliable check except in the case where the
Packit Service 82fcde
     caller has recursively called dlclose and we are sure the link map
Packit Service 82fcde
     has not been freed.  In a non-recursive dlclose the map itself
Packit Service 82fcde
     might have been freed and this access is potentially a data race
Packit Service 82fcde
     with whatever other use this memory might have now, or worse we
Packit Service 82fcde
     might silently corrupt memory if it looks enough like a link map.
Packit Service 82fcde
     POSIX has language in dlclose that appears to guarantee that this
Packit Service 82fcde
     should be a detectable case and given that dlclose should be threadsafe
Packit Service 82fcde
     we need this to be a reliable detection.
Packit Service 82fcde
     This is bug 20990. */
Packit Service 82fcde
  if (__builtin_expect (map->l_direct_opencount, 1) == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
      _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  _dl_close_worker (map, false);
Packit Service 82fcde
Packit Service 82fcde
  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
}