@@ -25,6 +25,7 @@
#include <stdio-lock.h>
#include <sys/single_threaded.h>
#include <unwind-link.h>
+#include <stdlib/setenv.h>
static void
fresetlockfiles (void)
@@ -64,6 +65,10 @@ __libc_fork (void)
_IO_list_lock ();
+ /* The setenv function acquires this lock, and then the malloc
+ locks. Use the same lock order here. */
+ __libc_lock_lock (__environ_lock);
+
/* Acquire malloc locks. This needs to come last because fork
handlers may use malloc, and the libio list lock has an
indirect malloc dependency as well (via the getdelim
@@ -87,6 +92,8 @@ __libc_fork (void)
/* Release malloc locks. */
call_function_static_weak (__malloc_fork_unlock_child);
+ __libc_lock_unlock (__environ_lock);
+
/* Reset the file list. These are recursive mutexes. */
fresetlockfiles ();
@@ -119,6 +126,8 @@ __libc_fork (void)
/* Release malloc locks, parent process variant. */
call_function_static_weak (__malloc_fork_unlock_parent);
+ __libc_lock_unlock (__environ_lock);
+
/* We execute this even if the 'fork' call failed. */
_IO_list_unlock ();
}
@@ -277,6 +277,7 @@ tests := \
tst-canon-bz26341 \
tst-cxa_atexit \
tst-environ \
+ tst-environ-fork \
tst-getenv-signal \
tst-getenv-thread \
tst-getenv-unsetenv \
@@ -639,6 +640,7 @@ $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3
$(objpfx)tst-qsort5: $(libm)
+$(objpfx)tst-environ-fork: $(shared-thread-library)
$(objpfx)tst-getenv-signal: $(shared-thread-library)
$(objpfx)tst-getenv-thread: $(shared-thread-library)
$(objpfx)tst-getenv-unsetenv: $(shared-thread-library)
@@ -19,7 +19,9 @@
#include <setenv.h>
#include <string.h>
#include <unistd.h>
+#include <libc-lock.h>
+__libc_lock_define_initialized (, __environ_lock);
struct environ_array *__environ_array_list;
environ_counter __environ_counter;
@@ -55,11 +55,8 @@ extern char **environ;
#endif
#if _LIBC
-/* This lock protects against simultaneous modifications of `environ'. */
-# include <libc-lock.h>
-__libc_lock_define_initialized (static, envlock)
-# define LOCK __libc_lock_lock (envlock)
-# define UNLOCK __libc_lock_unlock (envlock)
+# define LOCK __libc_lock_lock (__environ_lock)
+# define UNLOCK __libc_lock_unlock (__environ_lock)
#else
# define LOCK
# define UNLOCK
@@ -22,8 +22,12 @@
/* Not actually usable in rtld, but it is required for symbol discovery. */
#if IS_IN (libc) || IS_IN (rtld)
# include <atomic.h>
+# include <libc-lock.h>
# include <stdbool.h>
+/* This lock protects against simultaneous modifications of `environ'. */
+__libc_lock_define (extern, __environ_lock attribute_hidden);
+
/* We use an exponential sizing policy for environment arrays. The
arrays are not deallocating during the lifetime of the process.
This adds between one and two additional pointers per active
new file mode 100644
@@ -0,0 +1,38 @@
+/* Test environment snapshots with fork.
+ Copyright (C) 2024 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/>. */
+
+/* This test uses the process-creation skeleton, but does not performa
+ re-exec, so the use of PROGRAM is a bit misleading here. */
+
+#define PROGRAM "tst-environ-fork"
+#include "tst-environ-snapshot-skeleton.c"
+
+static pid_t
+create_process (void)
+{
+ pid_t pid = xfork ();
+ if (pid == 0)
+ {
+ verify_environ ();
+ /* Verify that it is possible to obtain the environment lock. */
+ TEST_COMPARE (setenv ("unrelated", "unrelated-set", 1), 0);
+ TEST_COMPARE_STRING (getenv ("unrelated"), "unrelated-set");
+ _exit (0);
+ }
+ return pid;
+}