This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/18657] New: DSO loaded with RTLD_NODELETE may get unloaded due to cxa_thread_atexit


https://sourceware.org/bugzilla/show_bug.cgi?id=18657

            Bug ID: 18657
           Summary: DSO loaded with RTLD_NODELETE may get unloaded due to
                    cxa_thread_atexit
           Product: glibc
           Version: unspecified
            Status: NEW
          Severity: normal
          Priority: P2
         Component: libc
          Assignee: unassigned at sourceware dot org
          Reporter: siddhesh at redhat dot com
                CC: drepper.fsp at gmail dot com
  Target Milestone: ---

When all destructors for objects registered with __cxa_thread_atexit_impl are
called, the __tls_call_dtors function clears the DF_1_NODELETE flag, which is
wrong since it could have been set by other means, like the RTLD_NODELETE flag
in dlopen or -z nodelete linker option.

Reproducer:

main.c:

#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

static void *
use_handle (void *h)
{ 
  void (*foo) (void) = (void (*) (void)) dlsym(h, "do_foo");

  if (!foo)
    {
      printf ("Unable to find symbol: %s\n", dlerror ());
      exit (1);
    }

  foo ();

  return NULL;
}

int
main ()
{
  pthread_t t;
  int ret;
  void *thr_ret;

  /* Load our module.  We access (and hence construct the object) in the
     thread.  */
  void *handle = dlopen ("$ORIGIN/tst-tls-atexit-lib.so", RTLD_LAZY);
  if (handle == NULL)
    {
      printf ("Unable to load DSO: %s\n", dlerror ());
      return 1;
    }

  if ((ret = pthread_create (&t, NULL, use_handle, handle)) != 0)
    {
      printf ("pthread_create failed: %s\n", strerror (ret));
      return 1;
    }

  if ((ret = pthread_join (t, &thr_ret)) != 0)
    {
      printf ("pthread_create failed: %s\n", strerror (ret));
      return 1;
    }

  if (thr_ret != NULL)
    return 1;

  /* This sequence should not unload the DSO.  */
  void *h2 = dlopen ("$ORIGIN/tst-tls-atexit-lib.so",
                     RTLD_LAZY | RTLD_NODELETE);
  if (h2 == NULL)
    {
      printf ("main thread: Unable to load DSO: %s\n", dlerror ());
      return 1;
    }

  use_handle (h2);

  /* Close the handle we created in the thread.  */
  dlclose (handle);
  dlclose (h2);

  /* Run through our maps and ensure that the DSO is unloaded.  */
  FILE *f = fopen ("/proc/self/maps", "r");

  if (f == NULL)
    {
      perror ("Failed to open /proc/self/maps");
      fprintf (stderr, "Skipping verification of DSO unload\n");
      return 0;
    }

  char *line = NULL;
  size_t s = 0;
  while (getline (&line, &s, f) > 0)
    {
      if (strstr (line, "tst-tls-atexit-lib.so"))
        {
          printf ("DSO not unloaded yet:\n%s", line);
          return 0;
        }
    }
  free (line);

  /* The module was unloaded even when we specified RTLD_NODELETE.  FAIL.  */
  printf ("tst-tls-atexit-lib.so was unloaded.\n");
  return 1;
}

tst-tls-atexit-lib.c:

#include <stdlib.h>

extern void *__dso_handle;

typedef struct
{
  void *val;
} A;

/* We only care about the destructor.  */
void A_dtor (void *obj)
{
  ((A *)obj)->val = obj;
}

void do_foo (void)
{
  static __thread A b;
  __cxa_thread_atexit_impl (A_dtor, &b, __dso_handle);
}

Patch coming up.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]