@@ -415,6 +415,7 @@ tests += \
tst-dlmopen3 \
tst-dlmopen4 \
tst-dlopen-auditdup \
+ tst-dlopen-constructor-null \
tst-dlopen-self \
tst-dlopen-tlsmodid \
tst-dlopen-tlsreinit1 \
@@ -868,6 +869,8 @@ modules-names += \
tst-dlmopen1mod \
tst-dlopen-auditdup-auditmod \
tst-dlopen-auditdupmod \
+ tst-dlopen-constructor-null-mod1 \
+ tst-dlopen-constructor-null-mod2 \
tst-dlopen-tlsreinitmod1 \
tst-dlopen-tlsreinitmod2 \
tst-dlopen-tlsreinitmod3 \
@@ -3160,3 +3163,9 @@ tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
$(objpfx)tst-dlopen-auditdup.out: \
$(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
+
+$(objpfx)tst-dlopen-constructor-null: \
+ $(objpfx)tst-dlopen-constructor-null-mod1.so \
+ $(objpfx)tst-dlopen-constructor-null-mod2.so
+$(objpfx)tst-dlopen-constructor-null-mod2.so: \
+ $(objpfx)tst-dlopen-constructor-null-mod1.so
@@ -594,6 +594,16 @@ dl_open_worker_begin (void *a)
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
add_to_global_update (new);
+ /* It is not possible to run the ELF constructor for the new
+ link map if it has not executed yet: If this dlopen call came
+ from an ELF constructor that has not put that object into a
+ consistent state, completing initialization for the entire
+ scope will expose objects that have this partially
+ constructed object among its dependencies to this
+ inconsistent state. This could happen even with a benign
+ dlopen (NULL, RTLD_LAZY) call from a constructor of an
+ initially loaded shared object. */
+
return;
}
new file mode 100644
@@ -0,0 +1,55 @@
+/* Module calling dlopen (NULL, RTLD_LAZY) to obtain the global scope.
+ 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/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int mod1_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ puts ("info: tst-dlopen-constructor-null-mod1.so constructor");
+
+ void *handle = dlopen (NULL, RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: %s\n", dlerror ());
+ exit (1);
+ }
+ puts ("info: dlopen returned");
+ if (dlsym (handle, "malloc") != malloc)
+ {
+ puts ("error: dlsym did not produce expected result");
+ exit (1);
+ }
+ dlclose (handle);
+
+ /* Check that the second module's constructor has not executed. */
+ if (getenv ("mod2_status") != NULL)
+ {
+ printf ("error: mod2_status environment variable set: %s\n",
+ getenv ("mod2_status"));
+ exit (1);
+ }
+
+ /* Communicate to the second module that the constructor executed. */
+ mod1_status = 1;
+}
new file mode 100644
@@ -0,0 +1,37 @@
+/* Module whose constructor should not be invoked by dlopen (NULL, RTLD_LAZY).
+ 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/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int mod1_status;
+int mod2_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ printf ("info: tst-dlopen-constructor-null-mod2.so constructor"
+ " (mod1_status=%d)", mod1_status);
+ if (!(mod1_status == 1 && mod2_status == 0))
+ {
+ puts ("error: mod1_status == 1 && mod2_status == 0 expected");
+ exit (1);
+ }
+ setenv ("mod2_status", "constructed", 1);
+ mod2_status = 1;
+}
new file mode 100644
@@ -0,0 +1,38 @@
+/* Verify that dlopen (NULL, RTLD_LAZY) does not complete initialization.
+ 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 mimics what the glvndSetupPthreads function in libglvnd
+ does. */
+
+#include <stdlib.h>
+#include <support/check.h>
+
+/* Defined an initialized in the shared objects. */
+extern int mod1_status;
+extern int mod2_status;
+
+static int
+do_test (void)
+{
+ TEST_COMPARE (mod1_status, 1);
+ TEST_COMPARE (mod2_status, 1);
+ TEST_COMPARE_STRING (getenv ("mod2_status"), "constructed");
+ return 0;
+}
+
+#include <support/test-driver.c>