NetBSD Problem Report #37347
From jtc@acorntoolworks.com Fri Nov 9 06:15:52 2007
Return-Path: <jtc@acorntoolworks.com>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
by narn.NetBSD.org (Postfix) with ESMTP id 4AC7A63B8D7
for <gnats-bugs@gnats.NetBSD.org>; Fri, 9 Nov 2007 06:15:52 +0000 (UTC)
Message-Id: <200711090615.lA96FopA013186@orac.acorntoolworks.com>
Date: Thu, 8 Nov 2007 22:15:50 -0800 (PST)
From: "J.T. Conklin" <jtc@acorntoolworks.com>
Reply-To: jtc@acorntoolworks.com
To: gnats-bugs@NetBSD.org
Subject: ld.elf_so does not execute .init/.fini functions in order
X-Send-Pr-Version: 3.95
>Number: 37347
>Category: bin
>Synopsis: ld.elf_so does not execute .init/.fini functions in order
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: lib-bug-people
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Nov 09 06:20:01 +0000 2007
>Closed-Date: Fri Oct 09 21:32:02 +0000 2009
>Last-Modified: Fri Oct 09 21:32:02 +0000 2009
>Originator: J.T. Conklin
>Release: NetBSD 4.0_RC3
>Organization:
J.T. Conklin
>Environment:
System: NetBSD vm1.acorntoolworks.com 4.0_RC3 NetBSD 4.0_RC3 (GENERIC) #0: Tue Oct 16 01:14:06 PDT 2007 builds@wb34:/home/builds/ab/netbsd-4-0-RC3/i386/200710160011Z-obj/home/builds/ab/netbsd-4-0-RC3/src/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386
>Description:
As reported in recent messages to tech-userland, I encountered
problems with ACE (A C++ Library/Framework) and TAO (A CORBA ORB
implementation that uses ACE) because TAO's static constructors
used the pthread library to create thread specific storage before
the pthread library was initialized itself.
Further discussion revealed that ld.elf_so did not perform the
required (topological) sort of the objects before executing the
.init/.fini functions in each shared library.
>How-To-Repeat:
Since ACE/TAO are huge libraries, I wrote a unit test. The program
"foobar" is linked with two shared libraries, "libfoo.so" and
"libbar.sh". "libbar.so" depends on "libfoo.so". To further
complicate things, "libfoo.so" dynamically loads "libtar.so" with
dlopen() in an .init function (freeing it in .fini), and "libtar.so"
depends on both "libbar.so" and "libfoo.so". Finally, the main
program foobar dynamically loads "libdll.so", which depends on
"libdep1.so" and "libdep2.so", and "libdep1.so" depends on
"libdep2.so".
The above may be difficult to visualize. Here is an ASCII diagram
that tries to show the dependencies.
foobar ----+---------------+
| |
libtar.so -+-> libbar.so -+-> libfoo.so
| |
+---------------+
libdll.so -+-> libdep1.so -+-> libdep2.so
| |
+---------------+
Each of the above shared libraries .init and .fini functions writes a
string to standard error, so you can see the order.
It should be:
$ ./foobar
foo_ctor
bar_ctor
tar_ctor
main_ctor
dep1_ctor
dep2_ctor
dll_ctor
dll_dtor
dep2_dtor
dep1_dtor
main_dtor
tar_dtor
bar_dtor
foo_dtor
While currently I get:
$ ./foobar
bar_ctor
foo_ctor
tar_ctor
main_ctor
dep1 ctor
dep2 ctor
dll ctor
dll dtor
dep2 dtor
dep1 dtor
main_dtor
foo_dtor
Invalid shared object handle 0xbdbed400
bar_dtor
tar_dtor
I tried this same test on FreeBSD 6.3, Solaris 10, and Ubuntu 7.10.
FreeBSD and Solaris seem to have had trouble with the dynamically
loaded libtar.so --- they both executed its .init function before
libbar.so's; but both got the destruction order correct. The test
produced the expected results on Ubuntu.
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# Makefile
# bar.c
# dep1.c
# dep2.c
# dll.c
# foo.c
# main.c
# tar.c
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
XCC=gcc
XCFLAGS=-O2
XLDFLAGS=-L. -R. # -Wl,--dynamic-linker,/tmp/ld.elf_so
X
Xall: barfoo foobar libdll.so libtar.so
X
Xclean:
X rm -f barfoo foobar *.o *.so
X
Xfoobar: libfoo.so libbar.so
X
Xbarfoo: libfoo.so libbar.so main.o
X $(CC) $(LDFLAGS) -o $@ main.o -lbar -lfoo
X
Xfoobar: libfoo.so libbar.so main.o
X $(CC) $(LDFLAGS) -o $@ main.o -lfoo -lbar
X
Xmain.o: main.c
X $(CC) $(CFLAGS) -o $@ -c main.c
X
Xfoo.o: foo.c
X $(CC) $(CFLAGS) -o $@ -fPIC -c foo.c
X
Xbar.o: bar.c
X $(CC) $(CFLAGS) -o $@ -fPIC -c bar.c
X
Xtar.o: tar.c
X $(CC) $(CFLAGS) -o $@ -fPIC -c tar.c
X
Xdll.o: dll.c
X $(CC) $(CFLAGS) -o $@ -fPIC -c dll.c
X
Xdep1.o: dep1.c
X $(CC) $(CFLAGS) -o $@ -fPIC -c dep1.c
X
Xdep2.o: dep2.c
X $(CC) $(CFLAGS) -o $@ -fPIC -c dep2.c
X
Xlibfoo.so: foo.o
X $(CC) $(LDFLAGS) -o $@ -shared foo.o -lc
X
Xlibbar.so: bar.o libfoo.so
X $(CC) $(LDFLAGS) -o $@ -shared bar.o -lfoo -lc
X
Xlibtar.so: tar.o libbar.so libfoo.so
X $(CC) $(LDFLAGS) -o $@ -shared tar.o -lbar -lfoo -lc
X
Xlibdll.so: dll.o libdep1.so libdep2.so
X $(CC) $(LDFLAGS) -o $@ -shared dll.o -ldep2 -ldep1 -lc
X
Xlibdep1.so: dep1.o libdep2.so
X $(CC) $(LDFLAGS) -o $@ -shared dep1.o -ldep2 -lc
X
Xlibdep2.so: dep2.o
X $(CC) $(LDFLAGS) -o $@ -shared dep2.o -lc
END-of-Makefile
echo x - bar.c
sed 's/^X//' >bar.c << 'END-of-bar.c'
X#include <unistd.h>
X
Xvoid bar_ctor() __attribute__((__constructor__));
Xvoid bar_dtor() __attribute__((__destructor__));
X
Xvoid
Xbar_ctor()
X{
X write(2, "bar_ctor\n", 9);
X}
X
Xvoid
Xbar_dtor()
X{
X write(2, "bar_dtor\n", 9);
X}
END-of-bar.c
echo x - dep1.c
sed 's/^X//' >dep1.c << 'END-of-dep1.c'
X#include <unistd.h>
X#include <dlfcn.h>
X
Xvoid *handle;
Xvoid dep1_ctor() __attribute__((__constructor__));
Xvoid dep1_dtor() __attribute__((__destructor__));
X
Xvoid
Xdep1_ctor()
X{
X write(2, "dep1 ctor\n", 10);
X handle = dlopen ("libfoo.so", RTLD_LAZY);
X}
X
Xvoid
Xdep1_dtor()
X{
X write(2, "dep1 dtor\n", 10);
X dlclose (handle);
X}
END-of-dep1.c
echo x - dep2.c
sed 's/^X//' >dep2.c << 'END-of-dep2.c'
X#include <unistd.h>
X
Xvoid dep_ctor() __attribute__((__constructor__));
Xvoid dep_dtor() __attribute__((__destructor__));
X
Xvoid
Xdep_ctor()
X{
X write(2, "dep2 ctor\n", 10);
X}
X
Xvoid
Xdep_dtor()
X{
X write(2, "dep2 dtor\n", 10);
X}
END-of-dep2.c
echo x - dll.c
sed 's/^X//' >dll.c << 'END-of-dll.c'
X#include <unistd.h>
X
Xvoid dll_ctor() __attribute__((__constructor__));
Xvoid dll_dtor() __attribute__((__destructor__));
X
Xvoid
Xdll_ctor()
X{
X write(2, "dll ctor\n", 9);
X}
X
Xvoid
Xdll_dtor()
X{
X write(2, "dll dtor\n", 9);
X}
END-of-dll.c
echo x - foo.c
sed 's/^X//' >foo.c << 'END-of-foo.c'
X#include <unistd.h>
X#include <dlfcn.h>
X
Xvoid *handle;
Xvoid foo_ctor() __attribute__((__constructor__));
Xvoid foo_dtor() __attribute__((__destructor__));
X
Xvoid
Xfoo_ctor()
X{
X write(2, "foo_ctor\n", 9);
X handle = dlopen("libtar.so", RTLD_LAZY);
X}
X
Xvoid
Xfoo_dtor()
X{
X write(2, "foo_dtor\n", 9);
X if (handle)
X dlclose(handle);
X}
END-of-foo.c
echo x - main.c
sed 's/^X//' >main.c << 'END-of-main.c'
X#include <unistd.h>
X#include <dlfcn.h>
X
Xvoid main_ctor() __attribute__((__constructor__));
Xvoid main_dtor() __attribute__((__destructor__));
X
Xvoid
Xmain_ctor()
X{
X write(2, "main_ctor\n", 10);
X}
X
Xvoid
Xmain_dtor()
X{
X write(2, "main_dtor\n", 10);
X}
X
Xint
Xmain()
X{
X void *handle;
X
X handle = dlopen("libdll.so", RTLD_LAZY);
X dlclose(handle);
X
X return 0;
X}
END-of-main.c
echo x - tar.c
sed 's/^X//' >tar.c << 'END-of-tar.c'
X#include <unistd.h>
X
Xvoid tar_ctor() __attribute__((__constructor__));
Xvoid tar_dtor() __attribute__((__destructor__));
X
Xvoid
Xtar_ctor()
X{
X write(2, "tar_ctor\n", 9);
X}
X
Xvoid
Xtar_dtor()
X{
X write(2, "tar_dtor\n", 9);
X}
END-of-tar.c
exit
>Fix:
The enclosed patch, relative to the netbsd-4 branch:
* replaces _rtld_objlist_add() with _rtld_objlist_push_head() and
_rtld_objlist_push_tail(). This allows the same sort routine to
be used for both .init and .fini.
* adds _rtld_objlist_clear(), which clears a list of objects list and
frees all elements.
* changes _rtld_call_fini_functions() to create a sorted object list,
invoke all .fini functions that have not been called, and dispose
the object list. A "force" parameter is used to indicate process
exit, otherwise only .fini is called only for those objects with a
zero reference count
* changes _rtld_call_init_functions() to create a sorted object list,
invoke all .init functions that have not been called, and dispose
the object list.
* adds a "init_done", "init_called", and "fini_called" flags to the
Obj_Entry structure. The first is used to mark an object visited
during the tsort. The others are used to ensure the .init and/or
.fini routes are not called more than once, especially when a
shared library is loaded/unloaded be a .init/.fini routine in
another shared library.
* adds _rtld_initlist_visit() and _rtld_initlist_tsort() functions
to perform the topological sort using a recursive depth first search.
Index: load.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/load.c,v
retrieving revision 1.31
diff -u -r1.31 load.c
--- load.c 21 Mar 2006 17:48:10 -0000 1.31
+++ load.c 9 Nov 2007 05:10:59 -0000
@@ -68,9 +68,19 @@
SIMPLEQ_HEAD_INITIALIZER(_rtld_list_main);
Objlist _rtld_list_global = /* Objects dlopened with RTLD_GLOBAL */
SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global);
+
+void
+_rtld_objlist_push_head(Objlist *list, Obj_Entry *obj)
+{
+ Objlist_Entry *elm;
+
+ elm = NEW(Objlist_Entry);
+ elm->obj = obj;
+ SIMPLEQ_INSERT_HEAD(list, elm, link);
+}
void
-_rtld_objlist_add(Objlist *list, Obj_Entry *obj)
+_rtld_objlist_push_tail(Objlist *list, Obj_Entry *obj)
{
Objlist_Entry *elm;
@@ -159,12 +169,12 @@
if (mode & RTLD_MAIN && !obj->mainref) {
obj->mainref = 1;
rdbg(("adding %p (%s) to _rtld_list_main", obj, obj->path));
- _rtld_objlist_add(&_rtld_list_main, obj);
+ _rtld_objlist_push_tail(&_rtld_list_main, obj);
}
if (mode & RTLD_GLOBAL && !obj->globalref) {
obj->globalref = 1;
rdbg(("adding %p (%s) to _rtld_list_global", obj, obj->path));
- _rtld_objlist_add(&_rtld_list_global, obj);
+ _rtld_objlist_push_tail(&_rtld_list_global, obj);
}
#endif
return obj;
Index: rtld.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/rtld.c,v
retrieving revision 1.111.2.1
diff -u -r1.111.2.1 rtld.c
--- rtld.c 19 Jul 2007 14:38:16 -0000 1.111.2.1
+++ rtld.c 9 Nov 2007 05:10:59 -0000
@@ -109,35 +109,64 @@
#endif /* RTLD_DEBUG */
extern Elf_Dyn _DYNAMIC;
-static void _rtld_call_fini_functions(Obj_Entry *);
-static void _rtld_call_init_functions(Obj_Entry *);
+static void _rtld_call_fini_functions(int);
+static void _rtld_call_init_functions(void);
+static void _rtld_initlist_visit(Objlist *, Obj_Entry *, int);
+static void _rtld_initlist_tsort(Objlist *, int);
static Obj_Entry *_rtld_dlcheck(void *);
static void _rtld_init_dag(Obj_Entry *);
static void _rtld_init_dag1(Obj_Entry *, Obj_Entry *);
static void _rtld_objlist_remove(Objlist *, Obj_Entry *);
+static void _rtld_objlist_clear(Objlist *);
static void _rtld_unload_object(Obj_Entry *, bool);
static void _rtld_unref_dag(Obj_Entry *);
static Obj_Entry *_rtld_obj_from_addr(const void *);
static void
-_rtld_call_fini_functions(Obj_Entry *first)
+_rtld_call_fini_functions(int force)
{
- Obj_Entry *obj;
+ Objlist_Entry *elm;
+ Objlist finilist;
+
+ dbg(("_rtld_call_fini_functions(%d)", force));
- for (obj = first; obj != NULL; obj = obj->next)
- if (obj->fini != NULL)
+ SIMPLEQ_INIT(&finilist);
+ _rtld_initlist_tsort(&finilist, 1);
+
+ SIMPLEQ_FOREACH(elm, &finilist, link) {
+ Obj_Entry *obj = elm->obj;
+ if ((force || obj->refcount == 0) && obj->fini != NULL && !obj->fini_called) {
+ dbg (("calling fini function %s at %p",
+ obj->path, (void *) obj->fini));
+ obj->fini_called = 1;
(*obj->fini)();
+ }
+ }
+
+ _rtld_objlist_clear(&finilist);
}
static void
-_rtld_call_init_functions(Obj_Entry *first)
+_rtld_call_init_functions()
{
+ Objlist_Entry *elm;
+ Objlist initlist;
- if (first != NULL) {
- _rtld_call_init_functions(first->next);
- if (first->init != NULL)
- (*first->init)();
+ dbg(("_rtld_call_init_functions()"));
+ SIMPLEQ_INIT(&initlist);
+ _rtld_initlist_tsort(&initlist, 0);
+
+ SIMPLEQ_FOREACH(elm, &initlist, link) {
+ Obj_Entry *obj = elm->obj;
+ if (obj->init != NULL && !obj->init_called) {
+ dbg (("calling init function %s at %p",
+ obj->path, (void *) obj->init));
+ obj->init_called = 1;
+ (*obj->init)();
+ }
}
+
+ _rtld_objlist_clear(&initlist);
}
/*
@@ -196,10 +225,9 @@
static void
_rtld_exit(void)
{
-
dbg(("rtld_exit()"));
- _rtld_call_fini_functions(_rtld_objlist->next);
+ _rtld_call_fini_functions(1);
}
/*
@@ -408,7 +436,7 @@
++_rtld_objmain->refcount;
_rtld_objmain->mainref = 1;
- _rtld_objlist_add(&_rtld_list_main, _rtld_objmain);
+ _rtld_objlist_push_tail(&_rtld_list_main, _rtld_objmain);
/* Initialize a fake symbol for resolving undefined weak references. */
_rtld_sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
@@ -463,7 +491,7 @@
*real___mainprog_obj = _rtld_objmain;
dbg(("calling _init functions"));
- _rtld_call_init_functions(_rtld_objmain->next);
+ _rtld_call_init_functions();
dbg(("control at program entry point = %p, obj = %p, exit = %p",
_rtld_objmain->entry, _rtld_objmain, _rtld_exit));
@@ -507,6 +535,46 @@
}
static void
+_rtld_initlist_visit(Objlist* list, Obj_Entry *obj, int rev)
+{
+ Needed_Entry* elm;
+
+// dbg(("_rtld_initlist_visit(%s)", obj->path));
+
+ if (obj->init_done)
+ return;
+ obj->init_done = 1;
+
+ for (elm = obj->needed; elm != NULL; elm = elm->next) {
+ if (elm->obj != NULL) {
+ _rtld_initlist_visit(list, elm->obj, rev);
+ }
+ }
+
+ if (rev) {
+ _rtld_objlist_push_head(list, obj);
+ } else {
+ _rtld_objlist_push_tail(list, obj);
+ }
+}
+
+static void
+_rtld_initlist_tsort(Objlist* list, int rev)
+{
+ dbg(("_rtld_initlist_tsort"));
+
+ Obj_Entry* obj;
+
+ for (obj = _rtld_objlist->next; obj; obj = obj->next) {
+ obj->init_done = 0;
+ }
+
+ for (obj = _rtld_objlist->next; obj; obj = obj->next) {
+ _rtld_initlist_visit(list, obj, rev);
+ }
+}
+
+static void
_rtld_init_dag(Obj_Entry *root)
{
@@ -523,8 +591,8 @@
return;
rdbg(("add %p (%s) to %p (%s) DAG", obj, obj->path, root,
root->path));
- _rtld_objlist_add(&obj->dldags, root);
- _rtld_objlist_add(&root->dagmembers, obj);
+ _rtld_objlist_push_tail(&obj->dldags, root);
+ _rtld_objlist_push_tail(&root->dagmembers, obj);
}
for (needed = obj->needed; needed != NULL; needed = needed->next)
if (needed->obj != NULL)
@@ -546,9 +614,7 @@
/* Finalize objects that are about to be unmapped. */
if (do_fini_funcs)
- for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
- if (obj->refcount == 0 && obj->fini != NULL)
- (*obj->fini)();
+ _rtld_call_fini_functions(0);
/* Remove the DAG from all objects' DAG lists. */
SIMPLEQ_FOREACH(elm, &root->dagmembers, link)
@@ -656,8 +722,9 @@
_rtld_unload_object(obj, false);
obj->dl_refcount--;
obj = NULL;
- } else
- _rtld_call_init_functions(obj);
+ } else {
+ _rtld_call_init_functions();
+ }
}
}
_rtld_debug.r_state = RT_CONSISTENT;
@@ -935,3 +1002,13 @@
free(elm);
}
}
+
+static void
+_rtld_objlist_clear(Objlist *list)
+{
+ while (!SIMPLEQ_EMPTY(list)) {
+ Objlist_Entry* elm = SIMPLEQ_FIRST(list);
+ SIMPLEQ_REMOVE_HEAD(list, link);
+ free(elm);
+ }
+}
Index: rtld.h
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/rtld.h,v
retrieving revision 1.73.4.1
diff -u -r1.73.4.1 rtld.h
--- rtld.h 27 Sep 2007 13:44:48 -0000 1.73.4.1
+++ rtld.h 9 Nov 2007 05:10:59 -0000
@@ -177,7 +177,12 @@
printed:1, /* True if ldd has printed it */
isdynamic:1, /* True if this is a pure PIC object */
mainref:1, /* True if on _rtld_list_main */
- globalref:1; /* True if on _rtld_list_global */
+ globalref:1, /* True if on _rtld_list_global */
+ init_done:1, /* True if .init has been added */
+ init_called:1, /* True if .init function has been
+ * called */
+ fini_called:1; /* True if .fini function has been
+ * called */
struct link_map linkmap; /* for GDB */
@@ -222,7 +227,8 @@
void _rtld_debug_state(void);
void _rtld_linkmap_add(Obj_Entry *);
void _rtld_linkmap_delete(Obj_Entry *);
-void _rtld_objlist_add(Objlist *, Obj_Entry *);
+void _rtld_objlist_push_head(Objlist *, Obj_Entry *);
+void _rtld_objlist_push_tail(Objlist *, Obj_Entry *);
Objlist_Entry *_rtld_objlist_find(Objlist *, const Obj_Entry *);
/* headers.c */
>Release-Note:
>Audit-Trail:
From: Andrew Doran <ad@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc: gnats-admin@netbsd.org, netbsd-bugs@netbsd.org,
christos@netbsd.org, mrg@netbsd.org
Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions in order
Date: Sun, 11 Nov 2007 01:54:03 +0000
On Fri, Nov 09, 2007 at 06:20:01AM +0000, J.T. Conklin wrote:
> As reported in recent messages to tech-userland, I encountered
> problems with ACE (A C++ Library/Framework) and TAO (A CORBA ORB
> implementation that uses ACE) because TAO's static constructors
> used the pthread library to create thread specific storage before
> the pthread library was initialized itself.
I have tried out the supplied patch and it works for me on -current with
free -> xfree. There is another problem: I see a lot of calls into
libpthread before it is initialized, and those calls are made from within
libc.
I think that the setup for libpthread should happen via a constructor in
libc, which solves the problem for me. Below is the libc bit; in libpthread
we just override __libc_thr_init().
Thanks,
Andrew
Index: lib/libc/thread-stub/thread-stub.c
===================================================================
RCS file: /cvsroot/src/lib/libc/thread-stub/thread-stub.c,v
retrieving revision 1.14
diff -u -p -r1.14 thread-stub.c
--- lib/libc/thread-stub/thread-stub.c 29 Nov 2005 03:12:00 -0000 1.14
+++ lib/libc/thread-stub/thread-stub.c 11 Nov 2007 01:46:42 -0000
@@ -74,6 +74,28 @@ do { \
#define CHECK_NOT_THREADED() /* nothing */
#endif
+/* libpthread init */
+
+void __libc_thr_init(void);
+void __libc_thr_init_stub(void);
+void __libc_thr_constructor(void) __attribute__((__constructor__));
+
+__weak_alias(__libc_thr_init,__libc_thr_init_stub)
+
+void
+__libc_thr_constructor(void)
+{
+
+ __libc_thr_init();
+}
+
+void
+__libc_thr_init_stub(void)
+{
+
+ /* nothing, may be overridden by libpthread */
+}
+
/* mutexes */
int __libc_mutex_init_stub(mutex_t *, const mutexattr_t *);
From: jtc@acorntoolworks.com (J.T. Conklin)
To: gnats-bugs@NetBSD.org
Cc: gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions in
order
Date: Sun, 11 Nov 2007 08:57:59 -0800
Andrew Doran <ad@NetBSD.org> writes:
> I have tried out the supplied patch and it works for me on -current with
> free -> xfree. There is another problem: I see a lot of calls into
> libpthread before it is initialized, and those calls are made from within
> libc.
> I think that the setup for libpthread should happen via a
> constructor in libc, which solves the problem for me. Below is the
> libc bit; in libpthread we just override __libc_thr_init().
libpthread doesn't record libc as a dependency, so even with my ld.so
patch the initialization order is undefined between the two libraries.
If this is fixed, libc constructors would deterministically call into
libpthread before libpthread is initialized. While deterministically
failing is better than intermittently succeeding, it points out that
something like Andrew's suggestion to have libc initialize libpthread
is needed.
--jtc
--
J.T. Conklin
From: Andrew Doran <ad@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc:
Subject: PR/37347 CVS commit: src/lib/libc
Date: Tue, 13 Nov 2007 15:21:21 +0000 (UTC)
Module Name: src
Committed By: ad
Date: Tue Nov 13 15:21:21 UTC 2007
Modified Files:
src/lib/libc: Makefile
src/lib/libc/sys: Makefile.inc
src/lib/libc/thread-stub: thread-stub.c
Added Files:
src/lib/libc/misc: Makefile.inc initfini.c stack_protector.c
Removed Files:
src/lib/libc/sys: stack_protector.c
Log Message:
- stack_protector.c doesn't really belong under sys/. Add a new directory
for misc support routines and put it there.
- Add a libc constructor. Use this to initialize threading and the
stack protector stuff. libpthread cannot be initialized safely using
its own constructor because libc and libpthread are deeply intertwined.
PR bin/37347
To generate a diff of this commit:
cvs rdiff -r1.131 -r1.132 src/lib/libc/Makefile
cvs rdiff -r0 -r1.1 src/lib/libc/misc/Makefile.inc \
src/lib/libc/misc/initfini.c src/lib/libc/misc/stack_protector.c
cvs rdiff -r1.179 -r1.180 src/lib/libc/sys/Makefile.inc
cvs rdiff -r1.5 -r0 src/lib/libc/sys/stack_protector.c
cvs rdiff -r1.14 -r1.15 src/lib/libc/thread-stub/thread-stub.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Andrew Doran <ad@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc:
Subject: PR/37347 CVS commit: src/lib/libpthread
Date: Tue, 13 Nov 2007 15:57:15 +0000 (UTC)
Module Name: src
Committed By: ad
Date: Tue Nov 13 15:57:15 UTC 2007
Modified Files:
src/lib/libpthread: pthread.c pthread_barrier.c pthread_cond.c
pthread_debug.c pthread_int.h pthread_lock.c pthread_mutex.c
pthread_rwlock.c pthread_rwlock2.c pthread_spin.c res_state.c
src/lib/libpthread/arch/i386: _context_u.S
src/lib/libpthread/arch/x86_64: _context_u.S
Log Message:
For PR bin/37347:
- Override __libc_thr_init() instead of using our own constructor.
- Add pthread__getenv() and use instead of getenv(). This is used before
we are up and running and unfortunatley getenv() takes locks.
Other changes:
- Cache the spinlock vectors in pthread__st. Internal spinlock operations
now take 1 function call instead of 3 (i386).
- Use pthread__self() internally, not pthread_self().
- Use __attribute__ ((visibility("hidden"))) in some places.
- Kill PTHREAD_MAIN_DEBUG.
To generate a diff of this commit:
cvs rdiff -r1.86 -r1.87 src/lib/libpthread/pthread.c
cvs rdiff -r1.14 -r1.15 src/lib/libpthread/pthread_barrier.c
cvs rdiff -r1.37 -r1.38 src/lib/libpthread/pthread_cond.c
cvs rdiff -r1.13 -r1.14 src/lib/libpthread/pthread_debug.c
cvs rdiff -r1.59 -r1.60 src/lib/libpthread/pthread_int.h
cvs rdiff -r1.31 -r1.32 src/lib/libpthread/pthread_lock.c
cvs rdiff -r1.36 -r1.37 src/lib/libpthread/pthread_mutex.c
cvs rdiff -r1.21 -r1.22 src/lib/libpthread/pthread_rwlock.c
cvs rdiff -r1.5 -r1.6 src/lib/libpthread/pthread_rwlock2.c
cvs rdiff -r1.2 -r1.3 src/lib/libpthread/pthread_spin.c
cvs rdiff -r1.4 -r1.5 src/lib/libpthread/res_state.c
cvs rdiff -r1.5 -r1.6 src/lib/libpthread/arch/i386/_context_u.S
cvs rdiff -r1.7 -r1.8 src/lib/libpthread/arch/x86_64/_context_u.S
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Andrew Doran <ad@netbsd.org>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions in order
Date: Sat, 1 Dec 2007 22:51:00 +0000
I've updated jtc's patch for -current:
http://www.netbsd.org/~ad/ld-current.diff
Andrew
From: christos@zoulas.com (Christos Zoulas)
To: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, jtc@acorntoolworks.com
Cc:
Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions in order
Date: Sat, 1 Dec 2007 18:35:35 -0500
On Dec 1, 10:55pm, ad@netbsd.org (Andrew Doran) wrote:
-- Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions i
| The following reply was made to PR bin/37347; it has been noted by GNATS.
|
| From: Andrew Doran <ad@netbsd.org>
| To: gnats-bugs@netbsd.org
| Cc:
| Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions in order
| Date: Sat, 1 Dec 2007 22:51:00 +0000
|
| I've updated jtc's patch for -current:
|
| http://www.netbsd.org/~ad/ld-current.diff
|
Why don't you commit it?
christos
From: Andrew Doran <ad@netbsd.org>
To: Christos Zoulas <christos@zoulas.com>
Cc: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, jtc@acorntoolworks.com
Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions in order
Date: Sat, 1 Dec 2007 23:49:47 +0000
On Sat, Dec 01, 2007 at 06:35:35PM -0500, Christos Zoulas wrote:
> On Dec 1, 10:55pm, ad@netbsd.org (Andrew Doran) wrote:
> -- Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions i
>
> | The following reply was made to PR bin/37347; it has been noted by GNATS.
> |
> | From: Andrew Doran <ad@netbsd.org>
> | To: gnats-bugs@netbsd.org
> | Cc:
> | Subject: Re: bin/37347: ld.elf_so does not execute .init/.fini functions in order
> | Date: Sat, 1 Dec 2007 22:51:00 +0000
> |
> | I've updated jtc's patch for -current:
> |
> | http://www.netbsd.org/~ad/ld-current.diff
> |
>
> Why don't you commit it?
I think it could use more test coverage. There is still another problem.
shlibs aren't linked directly against libc so there is no dependency
recorded.
libc and threads can get initialized very late on, while the constructors
for other shlibs are already making use of their facilities. We should
probably fix the link process but I'm beginning to think that we need some
sort of special case for libc. I'm not sure how else we can deal with all
the shlibs already out there.
This is from firefox-2 with the patch applied:
_rtld_call_init_functions()
_rtld_initlist_tsort
calling init function /usr/lib/libm387.so.0 at 0xbb379a00
calling init function /usr/lib/libm.so.0 at 0xbb35d740
calling init function /usr/lib/libpthread.so.0 at 0xbb262650
calling init function /usr/pkg/lib/firefox/libnspr4.so at 0xbba3fcc0
calling init function /usr/pkg/lib/firefox/libplds4.so at 0xbba6c9f0
calling init function /usr/pkg/lib/firefox/libplc4.so at 0xbba68f30
calling init function /usr/pkg/lib/firefox/libmozjs.so at 0xbbb51a70
calling init function /usr/lib/libstdc++.so.6 at 0xbb2b7f60
calling init function /usr/lib/libgcc_s.so.1 at 0xbb26d3b0
calling init function /usr/pkg/lib/firefox/libxpcom_core.so at 0xbbac13c0
calling init function /usr/pkg/lib/firefox/libxpcom.so at 0xbbb3e3b0
calling init function /usr/lib/libintl.so.0 at 0xbb37d6e0
calling init function /usr/pkg/lib/libglib-2.0.so.0 at 0xbb390650
calling init function /usr/pkg/lib/libgmodule-2.0.so.0 at 0xbb40eb50
calling init function /usr/pkg/lib/libgobject-2.0.so.0 at 0xbb417960
calling init function /usr/pkg/lib/libgdk_pixbuf-2.0.so.0 at 0xbb693f80
calling init function /usr/X11R6/lib/libX11.so.6 at 0xbb4508d0
calling init function /usr/X11R6/lib/libXext.so.6 at 0xbb67b3c0
calling init function /usr/X11R6/lib/libXi.so.6 at 0xbb6be0e0
calling init function /usr/pkg/lib/libpango-1.0.so.0 at 0xbb50e990
calling init function /usr/lib/libz.so.0 at 0xbb15e470
calling init function /usr/pkg/lib/libfreetype.so.6 at 0xbb555b80
calling init function /usr/pkg/lib/libexpat.so.1 at 0xbb0d4f70
calling init function /usr/pkg/lib/libfontconfig.so.1 at 0xbb5b1b80
calling init function /usr/pkg/lib/libglitz.so.1 at 0xbb13a140
calling init function /usr/pkg/lib/libpng12.so.0 at 0xbb11b120
calling init function /usr/pkg/lib/libXrender.so.1 at 0xbb5001b0
calling init function /usr/X11R6/lib/libICE.so.6 at 0xbb0f3c80
calling init function /usr/X11R6/lib/libSM.so.6 at 0xbb111d40
calling init function /usr/pkg/lib/libcairo.so.2 at 0xbb604420
calling init function /usr/pkg/lib/libpangoft2-1.0.so.0 at 0xbb5d9c90
calling init function /usr/pkg/lib/libpangocairo-1.0.so.0 at 0xbb68b6a0
calling init function /usr/pkg/lib/libXrandr.so.2 at 0xbb686b60
calling init function /usr/pkg/lib/libXfixes.so.0 at 0xbb663d90
calling init function /usr/pkg/lib/libXcursor.so.1 at 0xbb669c20
calling init function /usr/pkg/lib/libgdk-x11-2.0.so.0 at 0xbb6d6df0
calling init function /usr/pkg/lib/libatk-1.0.so.0 at 0xbb6aaab0
calling init function /usr/pkg/lib/libgtk-x11-2.0.so.0 at 0xbb787e30
calling init function /usr/lib/libz.so.1 at 0xbb53f2e0
calling init function /usr/lib/libc.so.12 at 0xbb186170
Doing a string match on the name isn't great, so I'm wondering if there
is another cheap way to identify it, like something in the ELF headers.
Andrew
From: Andrew Doran <ad@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc:
Subject: PR/37347 CVS commit: src
Date: Fri, 7 Dec 2007 20:34:06 +0000 (UTC)
Module Name: src
Committed By: ad
Date: Fri Dec 7 20:34:06 UTC 2007
Modified Files:
src/lib/libc: Makefile
src/libexec/ld.elf_so: headers.c load.c rtld.c rtld.h
src/sys/sys: exec_elf.h
Log Message:
rtld changes for PR bin/37347:
- Apply patch from J.T. Conklin to execute .init/.fini functions in order.
- Support DF_1_INITFIRST and mark libc with DF_1_INITFIRST. Shared libs
should be recording a dependency on libc, but it's too late to do that.
Ok christos@.
To generate a diff of this commit:
cvs rdiff -r1.132 -r1.133 src/lib/libc/Makefile
cvs rdiff -r1.22 -r1.23 src/libexec/ld.elf_so/headers.c
cvs rdiff -r1.34 -r1.35 src/libexec/ld.elf_so/load.c
cvs rdiff -r1.116 -r1.117 src/libexec/ld.elf_so/rtld.c
cvs rdiff -r1.75 -r1.76 src/libexec/ld.elf_so/rtld.h
cvs rdiff -r1.92 -r1.93 src/sys/sys/exec_elf.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Responsible-Changed-From-To: bin-bug-people->ad
Responsible-Changed-By: ad@netbsd.org
Responsible-Changed-When: Sun, 09 Dec 2007 03:55:03 +0000
Responsible-Changed-Why:
I got sucked in :)
State-Changed-From-To: open->analyzed
State-Changed-By: ad@netbsd.org
State-Changed-When: Sun, 09 Dec 2007 03:55:03 +0000
State-Changed-Why:
Not closing until pullups are done.
Responsible-Changed-From-To: ad->kern-bug-people
Responsible-Changed-By: ad@narn.netbsd.org
Responsible-Changed-When: Tue, 05 Feb 2008 15:09:49 +0000
Responsible-Changed-Why:
punt
State-Changed-From-To: analyzed->suspended
State-Changed-By: ad@narn.netbsd.org
State-Changed-When: Tue, 05 Feb 2008 15:09:49 +0000
State-Changed-Why:
I'm not sure it is safe to backport this to 4.0. pthread init relies
on a stack of bugs to work correctly and backporting the changes
may have unforseen effects. It would need a lot of testing.
Responsible-Changed-From-To: kern-bug-people->lib-bug-people
Responsible-Changed-By: ad@narn.netbsd.org
Responsible-Changed-When: Tue, 05 Feb 2008 15:14:17 +0000
Responsible-Changed-Why:
wrong category
State-Changed-From-To: suspended->feedback
State-Changed-By: ad@NetBSD.org
State-Changed-When: Wed, 28 May 2008 00:49:19 +0000
State-Changed-Why:
can this be closed?
From: Gary Duzan <gary@duzan.org>
To: gnats-bugs@NetBSD.org
Cc: netbsd-bugs@NetBSD.org, gnats-admin@NetBSD.org, christos@zoulas.com,
ad@netbsd.org
Subject: Re: bin/37347 (ld.elf_so does not execute .init/.fini functions in order)
Date: Sun, 17 May 2009 18:55:08 -0400
I know this comment is a bit late in coming, but I've only just
discovered the relationship of my bug to this one. The December 7,
2007, change to ld.elf_so seems to have broken finance/kmymoney2.
On startup the code hits a null pointer in a QString while trying
to run the static initializers for one of kmymoney's shared libraries.
It seems the Qt folks have anticipated the problem, though, since
they have an OS-specific workaround in place. Adding NetBSD to the
workaround lets kmymoney2 start up again:
===========================================================================
--- src/tools/qstring.cpp.orig 2007-02-02 09:01:05.000000000 -0500
+++ src/tools/qstring.cpp 2009-05-17 12:20:46.000000000 -0400
@@ -1362,7 +1362,7 @@
QStringData* QString::makeSharedNull()
{
QString::shared_null = new QStringData;
-#if defined( Q_OS_MAC ) || defined(Q_OS_SOLARIS) || defined(Q_OS_HPUX) || defined(Q_OS_AIX)
+#if defined( Q_OS_MAC ) || defined(Q_OS_SOLARIS) || defined(Q_OS_HPUX) || defined(Q_OS_AIX) || defined(Q_OS_NETBSD)
QString *that = const_cast<QString *>(&QString::null);
that->d = QString::shared_null;
#endif
===========================================================================
So the question is whether the change is a bug or if the previous
behavior was wrong. Personally, I wouldn't expect the above code
to set QString::shared_null to zero as I was seeing before the
workaround.
Gary Duzan
From: Thomas Klausner <wiz@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/37347 CVS commit: pkgsrc/x11/qt3-libs
Date: Wed, 20 May 2009 01:00:40 +0000
Module Name: pkgsrc
Committed By: wiz
Date: Wed May 20 01:00:40 UTC 2009
Modified Files:
pkgsrc/x11/qt3-libs: Makefile distinfo
pkgsrc/x11/qt3-libs/patches: patch-ar
Log Message:
Apply patch reported by Gary Duzan in PR 37347 to fix finance/kmymoney2
after ld.elf_so fix from December 2007.
Bump PKGREVISION.
To generate a diff of this commit:
cvs rdiff -u -r1.70 -r1.71 pkgsrc/x11/qt3-libs/Makefile
cvs rdiff -u -r1.49 -r1.50 pkgsrc/x11/qt3-libs/distinfo
cvs rdiff -u -r1.1 -r1.2 pkgsrc/x11/qt3-libs/patches/patch-ar
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
State-Changed-From-To: feedback->closed
State-Changed-By: dsl@NetBSD.org
State-Changed-When: Fri, 09 Oct 2009 21:32:02 +0000
State-Changed-Why:
As far as I can see, this is in 5.0 and won't be applied to o 4.X.
So no point leaving it open any longer!
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.