summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2021-01-19 09:26:31 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2021-01-21 10:39:27 -0300
commitaa0b91a5b4d35b5a5ee27ac8342a7d5deff78023 (patch)
tree949a0fa7dc9093dc20a5ef559a098d8775cd6d08
parentab406f43b81ed0f39d88d7dc75ddff06b617f0e8 (diff)
downloadglibc-azanella/_Fork.tar.gz
posix: Add _Fork [BZ #4737]azanella/_Fork
Austin Group issue 62 [1] droped the async-signal-safe requirement for fork and provided a asignal-signal-safe _Fork replacement that does not run the atfork handlers. It will be included in the future POSIX standard. It allow to close a long standing issue to make fork AS-safe (BZ#4737). As indicated on the bug, besides the internal lock for the atfork handlers itself; there is no guarantee that the handlers itself will not introduce more AS-safe issues. The idea is synchronize fork with the required internal locks to allow children in multithread processes to use mostly of standard function (even though POSIX states only AS-safe function should be used). On signal handles, _Fork should be used intead and only AS-safe functions should be used. For testing, the new tst-_Fork only check basic usage. I also added a new tst-mallocfork3 which uses the same strategy to check for deadlock of tst-mallocfork2 but using threads instead of subprocesses (and it does deadlock if it replaces _Fork with fork). [1] https://austingroupbugs.net/view.php?id=62
-rw-r--r--malloc/Makefile3
-rw-r--r--malloc/tst-mallocfork3.c213
-rw-r--r--posix/Makefile3
-rw-r--r--posix/Versions3
-rw-r--r--posix/fork.c8
-rw-r--r--posix/tst-_Fork.c218
-rw-r--r--posix/unistd.h7
-rw-r--r--sysdeps/mach/hurd/i386/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/alpha/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/arc/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/arm/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/arm/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/csky/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/hppa/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/i386/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/ia64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/nios2/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sh/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sh/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist1
40 files changed, 484 insertions, 4 deletions
diff --git a/malloc/Makefile b/malloc/Makefile
index 583bbefb0d..42852f47a2 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -31,6 +31,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-malloc-backtrace tst-malloc-thread-exit \
tst-malloc-thread-fail tst-malloc-fork-deadlock \
tst-mallocfork2 \
+ tst-mallocfork3 \
tst-interpose-nothread \
tst-interpose-thread \
tst-alloc_buffer \
@@ -110,6 +111,8 @@ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
$(objpfx)tst-malloc-backtrace: $(shared-thread-library)
$(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
+$(objpfx)tst-mallocfork3: $(shared-thread-library)
+$(objpfx)tst-mallocfork3-mcheck: $(shared-thread-library)
$(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library)
$(objpfx)tst-malloc-stats-cancellation: $(shared-thread-library)
$(objpfx)tst-malloc-backtrace-mcheck: $(shared-thread-library)
diff --git a/malloc/tst-mallocfork3.c b/malloc/tst-mallocfork3.c
new file mode 100644
index 0000000000..4ac99eea43
--- /dev/null
+++ b/malloc/tst-mallocfork3.c
@@ -0,0 +1,213 @@
+/* Test case for async-signal-safe _Fork (with respect to malloc).
+ Copyright (C) 2021 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; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+/* This test is similar to tst-mallocfork2.c, but specifically stress
+ the async-signal-safeness of _Fork on multithread environment. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/wait.h>
+
+/* How many malloc objects to keep arond. */
+enum { malloc_objects = 1009 };
+
+/* The maximum size of an object. */
+enum { malloc_maximum_size = 70000 };
+
+/* How many iterations the test performs before exiting. */
+enum { iterations = 10000 };
+
+/* Barrier for synchronization with the threads sending SIGUSR1
+ signals, to make it more likely that the signals arrive during a
+ fork/free/malloc call. */
+static pthread_barrier_t barrier;
+
+/* Set to 1 if SIGUSR1 is received. Used to detect a signal during
+ fork/free/malloc. */
+static volatile sig_atomic_t sigusr1_received;
+
+/* Periodically set to 1, to indicate that the thread is making
+ progress. Checked by liveness_signal_handler. */
+static volatile sig_atomic_t progress_indicator = 1;
+
+/* Set to 1 if an error occurs in the signal handler. */
+static volatile sig_atomic_t error_indicator = 0;
+
+static void
+sigusr1_handler (int signo)
+{
+ sigusr1_received = 1;
+
+ /* Perform a fork with a trivial subprocess. */
+ pid_t pid = _Fork ();
+ if (pid == -1)
+ {
+ write_message ("error: fork\n");
+ error_indicator = 1;
+ return;
+ }
+ if (pid == 0)
+ _exit (0);
+ int status;
+ int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (ret < 0)
+ {
+ write_message ("error: waitpid\n");
+ error_indicator = 1;
+ return;
+ }
+ if (status != 0)
+ {
+ write_message ("error: unexpected exit status from subprocess\n");
+ error_indicator = 1;
+ return;
+ }
+}
+
+static void
+liveness_signal_handler (int signo)
+{
+ if (progress_indicator)
+ progress_indicator = 0;
+ else
+ write_message ("warning: thread seems to be stuck\n");
+}
+
+struct signal_send_args
+{
+ pthread_t target;
+ int signo;
+ bool sleep;
+};
+#define SIGNAL_SEND_GET_ARG(arg, field) \
+ (((struct signal_send_args *)(arg))->field)
+
+/* Send SIGNO to the parent thread. If SLEEP, wait a second between
+ signals, otherwise use barriers to delay sending signals. */
+static void *
+signal_sender (void *args)
+{
+ int signo = SIGNAL_SEND_GET_ARG (args, signo);
+ bool sleep = SIGNAL_SEND_GET_ARG (args, sleep);
+
+ pthread_t target = SIGNAL_SEND_GET_ARG (args, target);
+ while (true)
+ {
+ if (!sleep)
+ xpthread_barrier_wait (&barrier);
+ xpthread_kill (target, signo);
+ if (sleep)
+ usleep (1 * 1000 * 1000);
+ else
+ xpthread_barrier_wait (&barrier);
+ }
+ return NULL;
+}
+
+static pthread_t sigusr1_sender[5];
+static pthread_t sigusr2_sender;
+
+static int
+do_test (void)
+{
+ xsignal (SIGUSR1, sigusr1_handler);
+ xsignal (SIGUSR2, liveness_signal_handler);
+
+ pthread_t self = pthread_self ();
+
+ struct signal_send_args sigusr2_args = { self, SIGUSR2, true };
+ sigusr2_sender = xpthread_create (NULL, signal_sender, &sigusr2_args);
+
+ /* Send SIGUSR1 signals from several threads. Hopefully, one
+ signal will hit one of the ciritical functions. Use a barrier to
+ avoid sending signals while not running fork/free/malloc. */
+ struct signal_send_args sigusr1_args = { self, SIGUSR1, false };
+ xpthread_barrier_init (&barrier, NULL,
+ array_length (sigusr1_sender) + 1);
+ for (size_t i = 0; i < array_length (sigusr1_sender); ++i)
+ sigusr1_sender[i] = xpthread_create (NULL, signal_sender, &sigusr1_args);
+
+ void *objects[malloc_objects] = {};
+ unsigned int fork_signals = 0;
+ unsigned int free_signals = 0;
+ unsigned int malloc_signals = 0;
+ unsigned int seed = 1;
+ for (int i = 0; i < iterations; ++i)
+ {
+ progress_indicator = 1;
+ int slot = rand_r (&seed) % malloc_objects;
+ size_t size = rand_r (&seed) % malloc_maximum_size;
+
+ /* Occasionally do a fork first, to catch deadlocks there as
+ well (see bug 24161). */
+ bool do_fork = (rand_r (&seed) % 7) == 0;
+
+ xpthread_barrier_wait (&barrier);
+ if (do_fork)
+ {
+ sigusr1_received = 0;
+ pid_t pid = _Fork ();
+ TEST_VERIFY_EXIT (pid != -1);
+ if (sigusr1_received)
+ ++fork_signals;
+ if (pid == 0)
+ _exit (0);
+ int status;
+ int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (ret < 0)
+ FAIL_EXIT1 ("waitpid: %m");
+ TEST_COMPARE (status, 0);
+ }
+ sigusr1_received = 0;
+ free (objects[slot]);
+ if (sigusr1_received)
+ ++free_signals;
+ sigusr1_received = 0;
+ objects[slot] = malloc (size);
+ if (sigusr1_received)
+ ++malloc_signals;
+ xpthread_barrier_wait (&barrier);
+
+ if (objects[slot] == NULL || error_indicator != 0)
+ {
+ printf ("error: malloc: %m\n");
+ return 1;
+ }
+ }
+
+ /* Clean up allocations. */
+ for (int slot = 0; slot < malloc_objects; ++slot)
+ free (objects[slot]);
+
+ printf ("info: signals received during fork: %u\n", fork_signals);
+ printf ("info: signals received during free: %u\n", free_signals);
+ printf ("info: signals received during malloc: %u\n", malloc_signals);
+
+ return 0;
+}
+
+#define TIMEOUT 100
+#include <support/test-driver.c>
diff --git a/posix/Makefile b/posix/Makefile
index b79b361fae..f0836fc624 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -113,7 +113,7 @@ test-srcs := globtest
tests += wordexp-test tst-exec tst-spawn tst-spawn2 tst-spawn3
endif
ifeq (yesyes,$(build-shared)$(have-thread-library))
-tests += tst-getopt-cancel
+tests += tst-getopt-cancel tst-_Fork
endif
tests-static = tst-exec-static tst-spawn-static
tests += $(tests-static)
@@ -282,6 +282,7 @@ $(objpfx)ptestcases.h: PTESTS PTESTS2C.sed
$(objpfx)runptests.o: $(objpfx)ptestcases.h
$(objpfx)tst-getopt-cancel: $(shared-thread-library)
+$(objpfx)tst-_Fork: $(shared-thread-library)
test-xfail-annexc = yes
$(objpfx)annexc.out: $(objpfx)annexc
diff --git a/posix/Versions b/posix/Versions
index 7d06a6d0c0..06d45e670f 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -147,6 +147,9 @@ libc {
}
GLIBC_2.30 {
}
+ GLIBC_2.33 {
+ _Fork;
+ }
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
__nanosleep_nocancel; __pause_nocancel;
diff --git a/posix/fork.c b/posix/fork.c
index 7f27fb8338..1c4481f9c2 100644
--- a/posix/fork.c
+++ b/posix/fork.c
@@ -40,9 +40,11 @@ __libc_fork (void)
{
/* Determine if we are running multiple threads. We skip some fork
handlers in the single-thread case, to make fork safer to use in
- signal handlers. POSIX requires that fork is async-signal-safe,
- but our current fork implementation is not. */
- bool multiple_threads = __libc_single_threaded;
+ signal handlers. Although POSIX has dropped async-signal-safe
+ requirement for fork (Austin Group tracker issue #62) this is
+ best effort to make is async-signal-safe at least for single-thread
+ case. */
+ bool multiple_threads = __libc_single_threaded == 0;
__run_fork_handlers (atfork_run_prepare, multiple_threads);
diff --git a/posix/tst-_Fork.c b/posix/tst-_Fork.c
new file mode 100644
index 0000000000..29a7ab6aaf
--- /dev/null
+++ b/posix/tst-_Fork.c
@@ -0,0 +1,218 @@
+/* Basic tests for _Fork.
+ Copyright (C) 2021 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 <string.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/xsignal.h>
+#include <support/temp_file.h>
+#include <support/xunistd.h>
+#include <support/xthread.h>
+
+/* For single-thread, _Fork behaves like fork. */
+static int
+singlethread_test (void)
+{
+ const char testdata1[] = "abcdefghijklmnopqrtuvwxz";
+ enum { testdatalen1 = array_length (testdata1) };
+ const char testdata2[] = "01234567890";
+ enum { testdatalen2 = array_length (testdata2) };
+
+ pid_t ppid = getpid ();
+
+ int tempfd = create_temp_file ("tst-_Fork", NULL);
+
+ /* Check if the opened file is shared between process by read and write
+ some data on parent and child processes. */
+ xwrite (tempfd, testdata1, testdatalen1);
+ off_t off = xlseek (tempfd, 0, SEEK_CUR);
+ TEST_COMPARE (off, testdatalen1);
+
+ pid_t pid = _Fork ();
+ TEST_VERIFY_EXIT (pid != -1);
+ if (pid == 0)
+ {
+ TEST_VERIFY_EXIT (getpid () != ppid);
+ TEST_COMPARE (getppid(), ppid);
+
+ TEST_COMPARE (xlseek (tempfd, 0, SEEK_CUR), testdatalen1);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ char buf[testdatalen1];
+ TEST_COMPARE (read (tempfd, buf, sizeof (buf)), testdatalen1);
+ TEST_COMPARE (memcmp (buf, testdata1, testdatalen1), 0);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ xwrite (tempfd, testdata2, testdatalen2);
+
+ close (tempfd);
+
+ _exit (EXIT_SUCCESS);
+ }
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status));
+ TEST_COMPARE (WEXITSTATUS (status), EXIT_SUCCESS);
+
+ TEST_COMPARE (xlseek (tempfd, 0, SEEK_CUR), testdatalen2);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ char buf[testdatalen2];
+ TEST_COMPARE (read (tempfd, buf, sizeof (buf)), testdatalen2);
+
+ TEST_COMPARE (memcmp (buf, testdata2, testdatalen2), 0);
+
+ return 0;
+}
+
+
+static volatile sig_atomic_t sigusr1_handler_ran;
+static pid_t sig_pid = -1;
+#define SIG_PID_EXIT_CODE 20
+
+static void
+sigusr1_handler (int signum)
+{
+ TEST_COMPARE (signum, SIGUSR1);
+
+ pid_t ppid = getpid ();
+
+ sig_pid = _Fork ();
+ TEST_VERIFY_EXIT (sig_pid != -1);
+ if (sig_pid == 0)
+ {
+ TEST_VERIFY_EXIT (getpid () != ppid);
+ TEST_COMPARE (getppid(), ppid);
+
+ _exit (SIG_PID_EXIT_CODE);
+ }
+
+ sigusr1_handler_ran = 1;
+}
+
+/* _Fork is async-signal-safe, so check if it can successfully issue
+ a new process in a signal handler. */
+static int
+singlethread_signal_test (void)
+{
+ xsignal (SIGUSR1, &sigusr1_handler);
+ /* Assume synchronous signal handling. */
+ xraise (SIGUSR1);
+ TEST_COMPARE (sigusr1_handler_ran, 1);
+
+ int status;
+ xwaitpid (sig_pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status));
+ TEST_COMPARE (WEXITSTATUS (status), SIG_PID_EXIT_CODE);
+
+ xsignal (SIGUSR1, SIG_DFL);
+
+ return 0;
+}
+
+
+static bool atfork_prepare_var;
+static bool atfork_parent_var;
+static bool atfork_child_var;
+
+static void
+atfork_prepare (void)
+{
+ atfork_prepare_var = true;
+}
+
+static void
+atfork_parent (void)
+{
+ atfork_parent_var = true;
+}
+
+static void
+atfork_child (void)
+{
+ atfork_child_var = true;
+}
+
+/* Different than fork, _Fork does not execute any pthread_atfork
+ handlers. */
+static int
+singlethread_atfork_test (void)
+{
+ pthread_atfork (atfork_prepare, atfork_parent, atfork_child);
+ singlethread_test ();
+ TEST_COMPARE (atfork_prepare_var, false);
+ TEST_COMPARE (atfork_parent_var, false);
+ TEST_COMPARE (atfork_child_var, false);
+
+ return 0;
+}
+
+
+static void *
+mt_atfork_test (void *args)
+{
+ singlethread_atfork_test ();
+
+ return NULL;
+}
+
+static int
+multithread_atfork_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, mt_atfork_test, NULL);
+ xpthread_join (thr);
+
+ return 0;
+}
+
+
+static void *
+mt_signal_test (void *args)
+{
+ singlethread_signal_test ();
+
+ return NULL;
+}
+
+static int
+multithread_signal_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, mt_signal_test, NULL);
+ xpthread_join (thr);
+
+ return 0;
+}
+
+
+static int
+do_test (void)
+{
+ singlethread_atfork_test ();
+ singlethread_signal_test ();
+
+ multithread_atfork_test ();
+ multithread_signal_test ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/unistd.h b/posix/unistd.h
index 3f22763379..670d471ac2 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -776,6 +776,13 @@ extern __pid_t fork (void) __THROWNL;
extern __pid_t vfork (void) __THROW;
#endif /* Use misc or XPG < 7. */
+#ifdef __USE_GNU
+/* This is similar to fork, however it does not run the atfork handlers
+ neither reinitialize any internal locks in multithread case.
+ Different than fork, _Fork is async-signal-safe. */
+extern __pid_t _Fork (void) __THROWNL;
+#endif
+
/* Return the pathname of the terminal FD is open on, or NULL on errors.
The returned storage is good only until the next call to this function. */
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 7a5eb66b85..c2650a5ab0 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2191,6 +2191,7 @@ GLIBC_2.32 thrd_current F
GLIBC_2.32 thrd_equal F
GLIBC_2.32 thrd_sleep F
GLIBC_2.32 thrd_yield F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 4cc1c6a591..8fcfaab95f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2160,6 +2160,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 26ad9845e4..d0965018fd 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2242,6 +2242,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bb9dfd4daf..2371371b76 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1920,6 +1920,7 @@ GLIBC_2.32 wprintf F
GLIBC_2.32 write F
GLIBC_2.32 writev F
GLIBC_2.32 wscanf F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 3b0a47e967..3159f140a8 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -144,6 +144,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 9ab3924888..c1b4333b81 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -141,6 +141,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 14a84dac8f..33397df96a 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2104,6 +2104,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 5c8502f3d3..6ec4ab13b2 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2063,6 +2063,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 4f0d3c1eb5..9dbffb7e5d 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2229,6 +2229,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e3b345b803..9363eb50eb 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2095,6 +2095,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 25f2d1c08f..d1c89dc88c 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -145,6 +145,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index c4891479d3..a109569de3 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2175,6 +2175,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 143b0163b4..2b7be37f55 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2155,6 +2155,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 13d374a031..990ab980da 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2152,6 +2152,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index b2295f1937..7fb0beff7a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2146,6 +2146,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 4c786070d0..7a56f4455e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2144,6 +2144,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index aa9c6a4dca..d90fdc9f55 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2152,6 +2152,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5939588ad5..e911f8bea8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2146,6 +2146,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 92556c4237..17b83975ba 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2193,6 +2193,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 26c93dff05..cd6af02e1b 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2202,6 +2202,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index f04b167788..aca40a93d7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2235,6 +2235,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index c2ca00709e..5366b736ba 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2065,6 +2065,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 0ea50dc851..4c93a9b685 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2355,6 +2355,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 0263e284d4..e026cbe814 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1,4 +1,5 @@
GLIBC_2.33 _Exit F
+GLIBC_2.33 _Fork F
GLIBC_2.33 _IO_2_1_stderr_ D 0xa0
GLIBC_2.33 _IO_2_1_stdin_ D 0xa0
GLIBC_2.33 _IO_2_1_stdout_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 1626c5351f..55bdaa3830 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2122,6 +2122,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index a66426eb4d..8bfb9ec6d6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2200,6 +2200,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index ab351873ae..1091cd7c7f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2101,6 +2101,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 22ceaa3d87..bbc0a56be2 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2070,6 +2070,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index d36f228192..3eb616f0f5 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2067,6 +2067,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 59b4313280..b3b405cc51 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2191,6 +2191,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 266dcdfa08..4d2dc42c6a 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2118,6 +2118,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 4fff61818b..81342513e7 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2076,6 +2076,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 102ed47a9c..70ae31674e 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2173,6 +2173,7 @@ GLIBC_2.32 sigabbrev_np F
GLIBC_2.32 sigdescr_np F
GLIBC_2.32 strerrordesc_np F
GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 _Fork F
GLIBC_2.33 fstat F
GLIBC_2.33 fstat64 F
GLIBC_2.33 fstatat F