Subject: broken exception handling and symbol lookup order
To: None <tech-toolchain@netbsd.org>
From: Michael Rauch <mrauch@netbsd.org>
List: tech-toolchain
Date: 11/30/2003 11:14:10
--SLDf9lqlvOQaIe6s
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi, 

while debugging a problem in the openoffice build process I found a case
where exception handling seems to be broken with gcc3/NetBSD-current:

There is a C++ program (regcomp) which opens (beyond other things) two
shared libraries (implreg.uno.so and simplereg.uno.so) via calls to
dlopen(...so, RTLD_GLOBAL). During the execution of the program it calls a
function f1 in implreg.uno.so which then in turn inside a try{} block calls a
function f2 in simplereg.uno.so. This f2 now throws an exception and it
should be caught from the corresponding catch block in f1. This doesn't
happen however, the eh framework walks up the stack where it finally aborts
because of an unhandled exception.

After some debugging I found out that both shared libraries have a reference
to "typeinfo for com::sun::star::registry::InvalidValueException" (the type
of the thrown exception). In _rtld_relocate_nonplt_objects in
src/libexec/ld.elf_so/arch/i386/mdreloc.c the two references are resolved to
different memory locations, while for shared libraries the program is linked
against references to other typeinfo entries all resolve to one single
memory location.  As the linker code on FreeBSD and NetBSD is more or less
the same, and the same code works for them, I searched for differences and
found the following change in the FreeBSD repository:
(I've attached the corresponding change for NetBSD as patch.)

CVS log for src/libexec/rtld-elf/rtld.c: Revision 1.68:
"Change the symbol lookup order to search RTLD_GLOBAL objects
 before referencing object's DAG. This makes it possible for
 C++ exceptions to work across shared libraries and brings
 us closer to the search order used by Solaris/Linux."

If I apply this patch, the failing exception can now be caught. I'm not a
toolchain expert, so I can't judge if that change is really correct.
What do you think?

My system:
$ uname -a
NetBSD zonk 1.6ZF NetBSD 1.6ZF (ZONK) #0: Sat Nov 29 17:16:39 CET 2003
root@:/usr/src/src/sys/arch/i386/compile/ZONK i386
(sources about 8 hours earlier)


Michael


--SLDf9lqlvOQaIe6s
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="netbsd.ld.elf_so.patch"

Index: libexec/ld.elf_so/symbol.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/symbol.c,v
retrieving revision 1.34
diff -u -r1.34 symbol.c
--- libexec/ld.elf_so/symbol.c	21 Oct 2003 01:19:10 -0000	1.34
+++ libexec/ld.elf_so/symbol.c	30 Nov 2003 10:11:29 -0000
@@ -224,12 +224,10 @@
 		}
 	}
 	
-	/* Search all dlopened DAGs containing the referencing object. */
-	SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
-		if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
-			break;
-		rdbg(("search DAG with root %p (%s)", elm->obj, elm->obj->path));
-		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
+	/* Search all RTLD_GLOBAL objects. */
+	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
+		rdbg(("search _rtld_list_global"));
+		symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
 		if (symp != NULL &&
 		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;
@@ -237,10 +235,12 @@
 		}
 	}
 	
-	/* Search all RTLD_GLOBAL objects. */
-	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-		rdbg(("search _rtld_list_global"));
-		symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
+	/* Search all dlopened DAGs containing the referencing object. */
+	SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
+		if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
+			break;
+		rdbg(("search DAG with root %p (%s)", elm->obj, elm->obj->path));
+		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
 		if (symp != NULL &&
 		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;

--SLDf9lqlvOQaIe6s--