diff options
author | Florian Weimer <fweimer@redhat.com> | 2023-07-06 19:24:33 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2023-07-06 19:24:33 +0200 |
commit | fb45e0aca9d0bf43d3086fc28e9e5bc66fe6500b (patch) | |
tree | c36707fe2c170e8c43161799fc307a0f3119264e | |
parent | e18c293af0ece38921ad71fbd76ff8049c3b2d67 (diff) | |
download | glibc-fw/bug30619.zip glibc-fw/bug30619.tar.gz glibc-fw/bug30619.tar.bz2 |
Test case for bug 30619fw/bug30619
-rw-r--r-- | sysdeps/pthread/Makefile | 9 | ||||
-rw-r--r-- | sysdeps/pthread/tst-thread-dlopen-fork-mod.c | 1 | ||||
-rw-r--r-- | sysdeps/pthread/tst-thread-dlopen-fork.c | 133 |
3 files changed, 143 insertions, 0 deletions
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index 32cf4eb..38b0a66 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -335,6 +335,7 @@ tests += \ tst-atfork3 \ tst-atfork4 \ tst-create1 \ + tst-thread-dlopen-fork \ tst-fini1 \ tst-pt-tls4 \ # tests @@ -351,6 +352,7 @@ modules-names += \ tst-atfork3mod \ tst-atfork4mod \ tst-create1mod \ + tst-thread-dlopen-fork-mod \ tst-fini1mod \ tst-tls4moda \ tst-tls4modb \ @@ -525,4 +527,11 @@ LDFLAGS-tst-create1 = -Wl,-export-dynamic $(objpfx)tst-create1: $(shared-thread-library) $(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so +# Create multiple shared objects to be used by the test. +tst-thread-dlopen-fork.sos := \ + $(patsubst %,$(objpfx)tst-thread-dlopen-fork-mod-%.so,$(shell seq 0 16)) +$(tst-thread-dlopen-fork.sos): $(objpfx)tst-thread-dlopen-fork-mod.so + cp -f $< $@ +$(objpfx)tst-thread-dlopen-fork.out: $(tst-thread-dlopen-fork.sos) + endif diff --git a/sysdeps/pthread/tst-thread-dlopen-fork-mod.c b/sysdeps/pthread/tst-thread-dlopen-fork-mod.c new file mode 100644 index 0000000..c219328 --- /dev/null +++ b/sysdeps/pthread/tst-thread-dlopen-fork-mod.c @@ -0,0 +1 @@ +/* Empty shared object. */ diff --git a/sysdeps/pthread/tst-thread-dlopen-fork.c b/sysdeps/pthread/tst-thread-dlopen-fork.c new file mode 100644 index 0000000..53d1279 --- /dev/null +++ b/sysdeps/pthread/tst-thread-dlopen-fork.c @@ -0,0 +1,133 @@ +/* Test that dlopen works after concurrent fork. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <array_length.h> +#include <stdlib.h> +#include <support/check.h> +#include <support/support.h> +#include <support/xdlfcn.h> +#include <support/xthread.h> +#include <support/xunistd.h> +#include <unistd.h> + +/* Use atomics to make sure that issues with dlopen/fork come from + implementation problems, and not from exposing the handle of a + partially initialized link map after dlopen returned. */ +static void *_Atomic handles[17]; + +/* Set to true if the dlopen thread has exited. */ +static _Atomic bool requested_exit; + +/* Used to start the forking and the dlopen thread at the same time. */ +static pthread_barrier_t barrier; + +/* Returns the file to open for IDX. */ +static char * +dso_name (int idx) +{ + return xasprintf ("tst-thread-dlopen-fork-mod-%d.so", idx); +} + +static void * +forking_thread (void *closure) +{ + xpthread_barrier_wait (&barrier); + int mode = 0; + while (!requested_exit) + { + pid_t pid = xfork (); + if (pid == 0) + { + switch (mode) + { + case 0: + /* Try to open all handles. */ + for (int i = 0; i < array_length (handles); ++i) + { + char *name = dso_name (i); + void *handle = xdlopen (name, RTLD_LAZY); + if (handles[i] != NULL) + TEST_VERIFY (handle == handles[i]); + free (name); + } + mode = 1; + break; + case 1: + /* Try to open all unopened handles. */ + for (int i = 0; i < array_length (handles); ++i) + if (handles[i] == NULL) + { + char *name = dso_name (i); + xdlopen (name, RTLD_LAZY); + free (name); + } + mode = 2; + break; + case 2: + /* Try to close all opened handles. */ + for (int i = 0; i < array_length (handles); ++i) + if (handles[i] != NULL) + xdlclose (handles[i]); + break; + } + _exit (0); + } + int status; + xwaitpid (pid, &status, 0); + TEST_COMPARE (status, 0); + } + return NULL; +} + +static void * +dlopen_thread (void *closure) +{ + xpthread_barrier_wait (&barrier); + srand (1); + for (int i = 0; i <= 1000; ++i) + { + int idx = rand () % array_length (handles); + void *handle = handles[idx]; + if (handle == NULL) + { + char *name = dso_name (idx); + handles[idx] = xdlopen (name, RTLD_LAZY); + free (name); + } + else + { + handles[idx] = NULL; + xdlclose (handle); + } + } + return NULL; +} + +static int +do_test (void) +{ + xpthread_barrier_init (&barrier, NULL, 2); + pthread_t thr_fork = xpthread_create (NULL, forking_thread, NULL); + pthread_t thr_dlopen = xpthread_create (NULL, dlopen_thread, NULL); + xpthread_join (thr_dlopen); + requested_exit = true; + xpthread_join (thr_fork); + return 0; +} + +#include <support/test-driver.c> |