This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH][BZ #15022] Correct global-scope dlopen issues in staticexecutables
On Wed, 16 Jan 2013, Roland McGrath wrote:
> As Joseph said, you should file two bugs with appropriate minimal test
> cases for the two issues. Then use [BZ #nnn] in the log entry for the
> change that affects the bug.
This is really a single bug only, triggering two different symptoms
depending on how you poke at the bug. The bug is the lack of global scope
in static executables. Now when you attempt to open that scope, as with
dlopen (NULL, ...), then owing to how its internals work the dynamic
loader engine tries to open a directory and treat it as a DSO. When on
the other hand you attempt to add a DSO to that scope, as with dlopen
("foo", RTLD_GLOBAL), then the engine crashes.
I have therefore created one bug report only, #15022.
> I would like to see a fix that does not change user-visible semantics at
> all (aside from not crashing, of course). If the change to the
> user-visible semantics of dlopen is desireable, then propose it
> separately. If it's inordinately difficult or ugly to fix the crash
> without the semantic change, then let the semantic change go in and
> settle first. If it's reasonably doable to fix the problems without the
> semantic change, then send the fixes first and then if the semantic
> change is desireable and goes in later, you can send additional cleanup
> changes to make the code simpler again afterwards.
Please elaborate on what user-visible semantics you would like
specifically to preserve.
> Each test case should be minimal and focussed on testing just one thing.
> For dynamic linking tests, that means they should use pure examples that
> only rely on linking behavior use trivial functions in the test itself.
> If it's worthwhile to test something having to do with the value
> returned by getpagesize, add that as separate test for getpagesize or
> whatever it is truly testing, not for linking behavior.
Well, some code paths can only be tested with more complicated scenarios
and whenever a test case regresses you probably want to run `git bisect'
on the tree anyway to find the offending change. Obviously you can't
verify that static DSO initialisation works correctly without referring to
code that relies on that, like the said getpagesize function.
Anyway I can see a benefit in having more limited cases as well, for
example to assess a regression quickly without having to look into it in
detail. So I have added two extra test cases now, modelled on the
original ones, that merely manipulate some data passed back and forth
between a static executable and a DSO, and making sure the changes
requested are as expected. I hope the two new tests meet your
expectations and fulfil your requirements.
Additionally, I made the error messages more verbose and unique, so that
any stage causing a failure is clearly identifiable by just looking at the
relevant test case source, without a need to attach with GDB or suchlike.
Finally, if you'd rather I split the getpagesize tests off and submitted
them separately, then I'm fine with that; obviously the tests would have
to be added after the bug fix itself or otherwise they would regress right
away.
I have smoke-tested the updated test cases, by running them on a
big-endian o32 MIPS target. If you agree this is the right change, then
I'll run full testing -- that'll take about a day. Otherwise I'll
appreciate your feedback. Thanks for your review.
2013-01-24 Maciej W. Rozycki <macro@codesourcery.com>
ChangeLog:
[BZ #15022]
* csu/libc-start.c (LIBC_START_MAIN) [!SHARED]: Prepare a global
search list.
* dlfcn/modstatic3.c: New file.
* dlfcn/modstatic5.c: New file.
* dlfcn/tststatic3.c: New file.
* dlfcn/tststatic4.c: New file.
* dlfcn/tststatic5.c: New file.
* dlfcn/tststatic6.c: New file.
* dlfcn/Makefile (tests): Add tststatic3, tststatic4, tststatic5
and tststatic6.
(tests-static): Likewise.
(modules-names): Add modstatic3 and modstatic5.
(tststatic3-ENV, tststatic4-ENV): New variables.
($(objpfx)tststatic3, $(objpfx)tststatic3.out): New dependencies.
($(objpfx)tststatic4, $(objpfx)tststatic4.out): Likewise.
($(objpfx)tststatic5, $(objpfx)tststatic5.out): Likewise.
($(objpfx)tststatic6, $(objpfx)tststatic6.out): Likewise.
ports/ChangeLog.ia64:
[BZ #15022]
* sysdeps/unix/sysv/linux/ia64/dl-static.c (_dl_static_init):
Exit right away if opening self.
ports/ChangeLog.mips:
[BZ #15022]
* sysdeps/unix/sysv/linux/mips/dl-static.c (_dl_static_init):
Exit right away if opening self.
Maciej
glibc-static-dlopen.diff
Index: glibc-fsf-trunk-quilt/csu/libc-start.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/csu/libc-start.c 2013-01-23 03:10:20.000000000 +0000
+++ glibc-fsf-trunk-quilt/csu/libc-start.c 2013-01-23 03:12:02.036666536 +0000
@@ -15,6 +15,7 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@@ -177,6 +178,26 @@ LIBC_START_MAIN (int (*main) (int, char
we need to setup errno. */
__pthread_initialize_minimal ();
+ /* Create a dummy link_map for the executable, used by dlopen to
+ access the global scope. We don't export any symbols ourselves,
+ so this can be minimal. */
+ struct link_map **new_global;
+ struct link_map *main_map;
+
+ main_map = _dl_new_object ("", "", lt_executable, NULL, 0, LM_ID_BASE);
+ assert (main_map != NULL);
+
+ _dl_add_to_namespace_list (main_map, LM_ID_BASE);
+ assert (main_map == GL(dl_ns)[LM_ID_BASE]._ns_loaded);
+ GL(dl_nns) = 1;
+
+ new_global = malloc (sizeof (struct link_map **));
+ assert (new_global != NULL);
+ *new_global = main_map;
+ main_map->l_searchlist.r_list = new_global;
+ main_map->l_searchlist.r_nlist = 1;
+ GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist = &main_map->l_searchlist;
+
/* Set up the stack checker's canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
Index: glibc-fsf-trunk-quilt/dlfcn/Makefile
===================================================================
--- glibc-fsf-trunk-quilt.orig/dlfcn/Makefile 2013-01-23 03:10:20.000000000 +0000
+++ glibc-fsf-trunk-quilt/dlfcn/Makefile 2013-01-24 10:10:35.846606720 +0000
@@ -47,11 +47,16 @@ glreflib2.so-no-z-defs = yes
errmsg1mod.so-no-z-defs = yes
ifeq (yes,$(build-shared))
-tests += tststatic tststatic2
-tests-static += tststatic tststatic2
-modules-names += modstatic modstatic2
+tests += tststatic tststatic2 tststatic3 tststatic4 tststatic5 tststatic6
+tests-static += tststatic tststatic2 tststatic3 tststatic4
+tests-static += tststatic5 tststatic6
+modules-names += modstatic modstatic2 modstatic3 modstatic5
tststatic-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
tststatic2-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
+tststatic3-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
+tststatic4-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
+tststatic5-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
+tststatic6-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
endif
extra-test-objs += $(modules-names:=.os)
@@ -104,6 +109,18 @@ $(objpfx)tststatic2.out: $(objpfx)tststa
$(objpfx)modstatic2.so: $(libdl)
+$(objpfx)tststatic3: $(objpfx)libdl.a
+$(objpfx)tststatic3.out: $(objpfx)tststatic3 $(objpfx)modstatic3.so
+
+$(objpfx)tststatic4: $(objpfx)libdl.a
+$(objpfx)tststatic4.out: $(objpfx)tststatic4 $(objpfx)modstatic3.so
+
+$(objpfx)tststatic5: $(objpfx)libdl.a
+$(objpfx)tststatic5.out: $(objpfx)tststatic5 $(objpfx)modstatic5.so
+
+$(objpfx)tststatic6: $(objpfx)libdl.a
+$(objpfx)tststatic6.out: $(objpfx)tststatic6 $(objpfx)modstatic5.so
+
$(objpfx)bug-dlopen1: $(libdl)
$(objpfx)bug-dlsym1: $(libdl) $(objpfx)bug-dlsym1-lib2.so
Index: glibc-fsf-trunk-quilt/dlfcn/modstatic3.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/dlfcn/modstatic3.c 2013-01-24 12:24:09.087820478 +0000
@@ -0,0 +1,30 @@
+/* Copyright (C) 2013 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
+ <http://www.gnu.org/licenses/>. */
+
+unsigned int foo;
+
+unsigned int
+getfoo (void)
+{
+ return foo;
+}
+
+unsigned int
+setfoo (unsigned int f)
+{
+ foo = f;
+}
Index: glibc-fsf-trunk-quilt/dlfcn/modstatic5.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/dlfcn/modstatic5.c 2013-01-23 03:12:02.036666536 +0000
@@ -0,0 +1,24 @@
+/* Copyright (C) 2013 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <unistd.h>
+
+int
+my_getpagesize (void)
+{
+ return getpagesize ();
+}
Index: glibc-fsf-trunk-quilt/dlfcn/tststatic3.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/dlfcn/tststatic3.c 2013-01-24 08:10:13.656588393 +0000
@@ -0,0 +1,114 @@
+/* Copyright (C) 2013 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ unsigned int (*getfoo) (void);
+ void (*setfoo) (unsigned int);
+ unsigned int *foop;
+ unsigned int foo;
+ void *handle;
+
+ handle = dlopen ("modstatic3.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (handle == NULL)
+ {
+ printf ("dlopen (modstatic3.so): %s\n", dlerror ());
+ return 1;
+ }
+
+ foop = dlsym (handle, "foo");
+ if (foop == NULL)
+ {
+ printf ("dlsym (foo): %s\n", dlerror ());
+ return 1;
+ }
+
+ getfoo = dlsym (handle, "getfoo");
+ if (getfoo == NULL)
+ {
+ printf ("dlsym (getfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ setfoo = dlsym (handle, "setfoo");
+ if (setfoo == NULL)
+ {
+ printf ("dlsym (setfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ foo = *foop;
+ if (foo != 0)
+ {
+ printf ("*foop: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ foo = getfoo ();
+ if (foo != 0)
+ {
+ printf ("getfoo: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ setfoo (0x5500ffaa);
+
+ foo = *foop;
+ if (foo != 0x5500ffaa)
+ {
+ printf ("*foop: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ foo = getfoo ();
+ if (foo != 0x5500ffaa)
+ {
+ printf ("getfoo: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ setfoo (0xaaff0055);
+
+ foo = *foop;
+ if (foo != 0xaaff0055)
+ {
+ printf ("*foop: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ foo = getfoo ();
+ if (foo != 0xaaff0055)
+ {
+ printf ("getfoo: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ getfoo = NULL;
+ setfoo = NULL;
+ foop = NULL;
+ dlclose (handle);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
Index: glibc-fsf-trunk-quilt/dlfcn/tststatic4.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/dlfcn/tststatic4.c 2013-01-24 08:12:43.657338293 +0000
@@ -0,0 +1,340 @@
+/* Copyright (C) 2013 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ unsigned int (*initial_getfoo) (void);
+ void (*initial_setfoo) (unsigned int);
+ unsigned int (*global_getfoo) (void);
+ void (*global_setfoo) (unsigned int);
+ unsigned int (*local_getfoo) (void);
+ void (*local_setfoo) (unsigned int);
+ unsigned int *initial_foop;
+ unsigned int *global_foop;
+ unsigned int *local_foop;
+ void *initial_handle;
+ void *global_handle;
+ void *local_handle;
+ unsigned int foo;
+
+ initial_handle = dlopen (NULL, RTLD_LAZY | RTLD_GLOBAL);
+ if (initial_handle == NULL)
+ {
+ printf ("dlopen [initial] (NULL): %s\n", dlerror ());
+ return 1;
+ }
+
+ initial_foop = dlsym (initial_handle, "foo");
+ if (initial_foop != NULL)
+ {
+ printf ("dlsym [initial] (foo): got %p, expected NULL\n", initial_foop);
+ return 1;
+ }
+
+ initial_getfoo = dlsym (initial_handle, "getfoo");
+ if (initial_getfoo != NULL)
+ {
+ printf ("dlsym [initial] (getfoo): got %p, expected NULL\n",
+ initial_getfoo);
+ return 1;
+ }
+
+ initial_setfoo = dlsym (initial_handle, "setfoo");
+ if (initial_setfoo != NULL)
+ {
+ printf ("dlsym [initial] (setfoo): got %p, expected NULL\n",
+ initial_setfoo);
+ return 1;
+ }
+
+ global_handle = dlopen ("modstatic3.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (global_handle == NULL)
+ {
+ printf ("dlopen [global] (modstatic3.so): %s\n", dlerror ());
+ return 1;
+ }
+
+ global_foop = dlsym (global_handle, "foo");
+ if (global_foop == NULL)
+ {
+ printf ("dlsym [global] (foo): %s\n", dlerror ());
+ return 1;
+ }
+
+ global_getfoo = dlsym (global_handle, "getfoo");
+ if (global_getfoo == NULL)
+ {
+ printf ("dlsym [global] (getfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ global_setfoo = dlsym (global_handle, "setfoo");
+ if (global_setfoo == NULL)
+ {
+ printf ("dlsym [global] (setfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ local_handle = dlopen (NULL, RTLD_LAZY | RTLD_LOCAL);
+ if (local_handle == NULL)
+ {
+ printf ("dlopen [local] (NULL): %s\n", dlerror ());
+ return 1;
+ }
+
+ local_foop = dlsym (local_handle, "foo");
+ if (local_foop == NULL)
+ {
+ printf ("dlsym [local] (foo): %s\n", dlerror ());
+ return 1;
+ }
+
+ local_getfoo = dlsym (local_handle, "getfoo");
+ if (local_getfoo == NULL)
+ {
+ printf ("dlsym [local] (getfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ local_setfoo = dlsym (local_handle, "setfoo");
+ if (local_setfoo == NULL)
+ {
+ printf ("dlsym [local] (setfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ initial_foop = dlsym (initial_handle, "foo");
+ if (initial_foop == NULL)
+ {
+ printf ("dlsym [local] (foo): %s\n", dlerror ());
+ return 1;
+ }
+
+ initial_getfoo = dlsym (initial_handle, "getfoo");
+ if (initial_getfoo == NULL)
+ {
+ printf ("dlsym [local] (getfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ initial_setfoo = dlsym (initial_handle, "setfoo");
+ if (initial_setfoo == NULL)
+ {
+ printf ("dlsym [local] (setfoo): %s\n", dlerror ());
+ return 1;
+ }
+
+ foo = *initial_foop;
+ if (foo != 0)
+ {
+ printf ("*foop [initial]: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ foo = *global_foop;
+ if (foo != 0)
+ {
+ printf ("*foop [global]: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ foo = *local_foop;
+ if (foo != 0)
+ {
+ printf ("*foop [local]: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ foo = initial_getfoo ();
+ if (foo != 0)
+ {
+ printf ("getfoo [initial]: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ foo = global_getfoo ();
+ if (foo != 0)
+ {
+ printf ("getfoo [global]: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ foo = local_getfoo ();
+ if (foo != 0)
+ {
+ printf ("getfoo [local]: got 0x%x, expected 0x0\n", foo);
+ return 1;
+ }
+
+ initial_setfoo (0x5500ffaa);
+
+ foo = *initial_foop;
+ if (foo != 0x5500ffaa)
+ {
+ printf ("*foop [initial]: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ foo = *global_foop;
+ if (foo != 0x5500ffaa)
+ {
+ printf ("*foop [global]: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ foo = *local_foop;
+ if (foo != 0x5500ffaa)
+ {
+ printf ("*foop [local]: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ foo = initial_getfoo ();
+ if (foo != 0x5500ffaa)
+ {
+ printf ("getfoo [initial]: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ foo = global_getfoo ();
+ if (foo != 0x5500ffaa)
+ {
+ printf ("getfoo [global]: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ foo = local_getfoo ();
+ if (foo != 0x5500ffaa)
+ {
+ printf ("getfoo [local]: got 0x%x, expected 0x5500ffaa\n", foo);
+ return 1;
+ }
+
+ global_setfoo (0xaaff0055);
+
+ foo = *initial_foop;
+ if (foo != 0xaaff0055)
+ {
+ printf ("*foop [initial]: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ foo = *global_foop;
+ if (foo != 0xaaff0055)
+ {
+ printf ("*foop [global]: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ foo = *local_foop;
+ if (foo != 0xaaff0055)
+ {
+ printf ("*foop [local]: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ foo = initial_getfoo ();
+ if (foo != 0xaaff0055)
+ {
+ printf ("getfoo [initial]: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ foo = global_getfoo ();
+ if (foo != 0xaaff0055)
+ {
+ printf ("getfoo [global]: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ foo = local_getfoo ();
+ if (foo != 0xaaff0055)
+ {
+ printf ("getfoo [local]: got 0x%x, expected 0xaaff0055\n", foo);
+ return 1;
+ }
+
+ local_setfoo (0xff55aa00);
+
+ foo = *initial_foop;
+ if (foo != 0xff55aa00)
+ {
+ printf ("*foop [initial]: got 0x%x, expected 0xff55aa00\n", foo);
+ return 1;
+ }
+
+ foo = *global_foop;
+ if (foo != 0xff55aa00)
+ {
+ printf ("*foop [global]: got 0x%x, expected 0xff55aa00\n", foo);
+ return 1;
+ }
+
+ foo = *local_foop;
+ if (foo != 0xff55aa00)
+ {
+ printf ("*foop [local]: got 0x%x, expected 0xff55aa00\n", foo);
+ return 1;
+ }
+
+ foo = initial_getfoo ();
+ if (foo != 0xff55aa00)
+ {
+ printf ("getfoo [initial]: got 0x%x, expected 0xff55aa00\n", foo);
+ return 1;
+ }
+
+ foo = global_getfoo ();
+ if (foo != 0xff55aa00)
+ {
+ printf ("getfoo [global]: got 0x%x, expected 0xff55aa00\n", foo);
+ return 1;
+ }
+
+ foo = local_getfoo ();
+ if (foo != 0xff55aa00)
+ {
+ printf ("getfoo [local]: got 0x%x, expected 0xff55aa00\n", foo);
+ return 1;
+ }
+
+ initial_getfoo = NULL;
+ initial_setfoo = NULL;
+ initial_foop = NULL;
+
+ local_getfoo = NULL;
+ local_setfoo = NULL;
+ local_foop = NULL;
+ dlclose (local_handle);
+
+ global_getfoo = NULL;
+ global_setfoo = NULL;
+ global_foop = NULL;
+ dlclose (global_handle);
+
+ dlclose (initial_handle);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
Index: glibc-fsf-trunk-quilt/dlfcn/tststatic5.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/dlfcn/tststatic5.c 2013-01-24 08:09:14.486499700 +0000
@@ -0,0 +1,59 @@
+/* Copyright (C) 2013 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ int pagesize = getpagesize ();
+ int (*my_getpagesize) (void);
+ int my_pagesize;
+ void *handle;
+
+ handle = dlopen ("modstatic5.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (handle == NULL)
+ {
+ printf ("dlopen (modstatic5.so): %s\n", dlerror ());
+ return 1;
+ }
+
+ my_getpagesize = dlsym (handle, "my_getpagesize");
+ if (my_getpagesize == NULL)
+ {
+ printf ("dlsym (my_getpagesize): %s\n", dlerror ());
+ return 1;
+ }
+
+ my_pagesize = my_getpagesize ();
+ if (my_pagesize != pagesize)
+ {
+ printf ("my_getpagesize: got %i, expected %i\n", my_pagesize, pagesize);
+ return 1;
+ }
+
+ my_getpagesize = NULL;
+ dlclose (handle);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
Index: glibc-fsf-trunk-quilt/dlfcn/tststatic6.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/dlfcn/tststatic6.c 2013-01-24 08:08:54.587145321 +0000
@@ -0,0 +1,125 @@
+/* Copyright (C) 2013 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ int (*my_initial_getpagesize) (void);
+ int (*my_global_getpagesize) (void);
+ int (*my_local_getpagesize) (void);
+ int pagesize = getpagesize ();
+ int my_initial_pagesize;
+ int my_global_pagesize;
+ int my_local_pagesize;
+ void *initial_handle;
+ void *global_handle;
+ void *local_handle;
+
+ initial_handle = dlopen (NULL, RTLD_LAZY | RTLD_GLOBAL);
+ if (initial_handle == NULL)
+ {
+ printf ("dlopen [initial] (NULL): %s\n", dlerror ());
+ return 1;
+ }
+
+ my_initial_getpagesize = dlsym (initial_handle, "my_getpagesize");
+ if (my_initial_getpagesize != NULL)
+ {
+ printf ("dlsym [initial] (my_getpagesize): got %p, expected NULL\n",
+ my_initial_getpagesize);
+ return 1;
+ }
+
+ global_handle = dlopen ("modstatic5.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (global_handle == NULL)
+ {
+ printf ("dlopen [global] (modstatic5.so): %s\n", dlerror ());
+ return 1;
+ }
+
+ my_global_getpagesize = dlsym (global_handle, "my_getpagesize");
+ if (my_global_getpagesize == NULL)
+ {
+ printf ("dlsym [global] (my_getpagesize): %s\n", dlerror ());
+ return 1;
+ }
+
+ local_handle = dlopen (NULL, RTLD_LAZY | RTLD_LOCAL);
+ if (local_handle == NULL)
+ {
+ printf ("dlopen [local] (NULL): %s\n", dlerror ());
+ return 1;
+ }
+
+ my_local_getpagesize = dlsym (local_handle, "my_getpagesize");
+ if (my_local_getpagesize == NULL)
+ {
+ printf ("dlsym [local] (my_getpagesize): %s\n", dlerror ());
+ return 1;
+ }
+
+ my_initial_getpagesize = dlsym (initial_handle, "my_getpagesize");
+ if (my_initial_getpagesize == NULL)
+ {
+ printf ("dlsym [initial] (my_getpagesize): %s\n", dlerror ());
+ return 1;
+ }
+
+ my_initial_pagesize = my_initial_getpagesize ();
+ if (my_initial_pagesize != pagesize)
+ {
+ printf ("my_getpagesize [initial]: got %i, expected %i\n",
+ my_initial_pagesize, pagesize);
+ return 1;
+ }
+
+ my_global_pagesize = my_global_getpagesize ();
+ if (my_global_pagesize != pagesize)
+ {
+ printf ("my_getpagesize [global]: got %i, expected %i\n",
+ my_global_pagesize, pagesize);
+ return 1;
+ }
+
+ my_local_pagesize = my_local_getpagesize ();
+ if (my_local_pagesize != pagesize)
+ {
+ printf ("my_getpagesize [local]: got %i, expected %i\n",
+ my_local_pagesize, pagesize);
+ return 1;
+ }
+
+ my_initial_getpagesize = NULL;
+
+ my_local_getpagesize = NULL;
+ dlclose (local_handle);
+
+ my_global_getpagesize = NULL;
+ dlclose (global_handle);
+
+ dlclose (initial_handle);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/ia64/dl-static.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/ia64/dl-static.c 2013-01-23 03:10:20.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/ia64/dl-static.c 2013-01-23 03:12:02.047777535 +0000
@@ -52,6 +52,10 @@ _dl_static_init (struct link_map *map)
lookup_t loadbase;
void (*f) (void *[]);
+ /* Nothing to do if opening self. */
+ if (__builtin_expect (map->l_name[0] == '\0', 0))
+ return;
+
__libc_lock_lock_recursive (_dl_static_lock);
loadbase = _dl_lookup_symbol_x ("_dl_var_init", map, &ref,
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/dl-static.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/dl-static.c 2013-01-23 03:10:20.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/dl-static.c 2013-01-23 03:12:02.047777535 +0000
@@ -64,6 +64,10 @@ _dl_static_init (struct link_map *l)
void (*f) (void *[]);
size_t i;
+ /* Nothing to do if opening self. */
+ if (__builtin_expect (l->l_name[0] == '\0', 0))
+ return;
+
__libc_lock_lock_recursive (_dl_static_lock);
loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope,