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:

NetBSD Home
NetBSD PR Database Search

(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.