mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-04 10:50:07 +00:00
Test case for bug 30619
This commit is contained in:
parent
e18c293af0
commit
fb45e0aca9
@ -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
|
||||
|
1
sysdeps/pthread/tst-thread-dlopen-fork-mod.c
Normal file
1
sysdeps/pthread/tst-thread-dlopen-fork-mod.c
Normal file
@ -0,0 +1 @@
|
||||
/* Empty shared object. */
|
133
sysdeps/pthread/tst-thread-dlopen-fork.c
Normal file
133
sysdeps/pthread/tst-thread-dlopen-fork.c
Normal file
@ -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>
|
Loading…
Reference in New Issue
Block a user