diff options
Diffstat (limited to 'stdlib/tst-tls-atexit.c')
-rw-r--r-- | stdlib/tst-tls-atexit.c | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/stdlib/tst-tls-atexit.c b/stdlib/tst-tls-atexit.c index cea655decc..e9839d8b15 100644 --- a/stdlib/tst-tls-atexit.c +++ b/stdlib/tst-tls-atexit.c @@ -16,12 +16,20 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -/* This test dynamically loads a DSO and spawns a thread that subsequently - calls into the DSO to register a destructor for an object in the DSO and - then calls dlclose on the handle for the DSO. When the thread exits, the - DSO should not be unloaded or else the destructor called during thread exit - will crash. Further in the main thread, the DSO is opened and closed again, - at which point the DSO should be unloaded. */ +/* For the default case, i.e. NO_DELETE not defined, the test dynamically loads + a DSO and spawns a thread that subsequently calls into the DSO to register a + destructor for an object in the DSO and then calls dlclose on the handle for + the DSO. When the thread exits, the DSO should not be unloaded or else the + destructor called during thread exit will crash. Further in the main + thread, the DSO is opened and closed again, at which point the DSO should be + unloaded. + + When NO_DELETE is defined, the DSO is loaded twice, once with just RTLD_LAZY + flag and the second time with the RTLD_NODELETE flag set. The thread is + spawned, destructor registered and then thread exits without closing the + DSO. In the main thread, the first handle is then closed, followed by the + second handle. In the end, the DSO should remain loaded due to the + RTLD_NODELETE flag being set in the second dlopen call. */ #include <dlfcn.h> #include <pthread.h> @@ -31,6 +39,14 @@ #include <errno.h> #include <link.h> +#ifndef NO_DELETE +# define LOADED_IS_GOOD false +#endif + +#ifndef H2_RTLD_FLAGS +# define H2_RTLD_FLAGS (RTLD_LAZY) +#endif + #define DSO_NAME "$ORIGIN/tst-tls-atexit-lib.so" /* Walk through the map in the _r_debug structure to see if our lib is still @@ -43,7 +59,10 @@ is_loaded (void) for (; lm; lm = lm->l_next) if (lm->l_type == lt_loaded && lm->l_name && strcmp (basename (DSO_NAME), basename (lm->l_name)) == 0) - return true; + { + printf ("%s is still loaded\n", lm->l_name); + return true; + } return false; } @@ -63,7 +82,9 @@ reg_dtor_and_close (void *h) reg_dtor (); +#ifndef NO_DELETE dlclose (h); +#endif return NULL; } @@ -104,19 +125,30 @@ do_test (void) return 1; } +#ifndef NO_DELETE if (spawn_thread (h1) != 0) return 1; +#endif - /* Now this should unload the DSO. FIXME: This is a bug, calling dlclose - like this is actually wrong, but it works because cxa_thread_atexit_impl - has a bug which results in dlclose allowing this to work. */ - dlclose (h1); + void *h2 = dlopen (DSO_NAME, H2_RTLD_FLAGS); + if (h2 == NULL) + { + printf ("h2: Unable to load DSO: %s\n", dlerror ()); + return 1; + } - /* Check link maps to ensure that the DSO has unloaded. */ - if (is_loaded ()) +#ifdef NO_DELETE + if (spawn_thread (h1) != 0) return 1; - return 0; + dlclose (h1); +#endif + dlclose (h2); + + /* Check link maps to ensure that the DSO has unloaded. In the normal case, + the DSO should be unloaded if there are no uses. However, if one of the + dlopen calls were with RTLD_NODELETE, the DSO should remain loaded. */ + return is_loaded () == LOADED_IS_GOOD ? 0 : 1; } #define TEST_FUNCTION do_test () |