This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug libc/18657] New: DSO loaded with RTLD_NODELETE may get unloaded due to cxa_thread_atexit
- From: "siddhesh at redhat dot com" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sourceware dot org
- Date: Fri, 10 Jul 2015 18:08:17 +0000
- Subject: [Bug libc/18657] New: DSO loaded with RTLD_NODELETE may get unloaded due to cxa_thread_atexit
- Auto-submitted: auto-generated
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.