dynamic_cast incorrectly returns 0 in programs that load dynamic shared objects (DSOs) via dlopen(). Header file <typeinfo> assumes that typeinfo names are merged across all DSOs in a program if weak symbols are supported. At least on Linux, this assumption is wrong for DSOs loaded via dlopen(). Note: This is more or less the same bug report as #4292; a workaround was suggested for #4292, and the case was closed. The workaround -- using dlopen(..., RTLD_NOW | RTLD_GLOBAL) -- does not work, so I am resubmitting the bug with an updated example. Release: unknown Environment: gcc 3.0.1 / 3.0.2 on RedHat Linux 7.1 / Pentium % g++ -v Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.0.1/specs Configured with: ../gcc-3.0.1/configure --enable-threads --prefix=/usr/local --enable-languages=c,c++ Thread model: posix gcc version 3.0.1 How-To-Repeat: Reproducing the bug requires multiple source files: a.C a.h main.C Makefile The files are listed below. The example program should print: castInMain() 1 castInDso() 1 castInMain() 1 castInDso() 1 The program prints this instead: castInMain() 1 castInDso() 0 castInMain() 0 castInDso() 1 The source files: :::::::::::::: a.C :::::::::::::: #include <a.h> #include <iostream> extern "C" { D * DInDso () { static D d; return &d; } bool castInDso (B *b) { std::cout << "castInDso()\n"; return 0 != dynamic_cast <D *> (b); } } :::::::::::::: a.h :::::::::::::: struct B { virtual ~B() {} }; struct D: public B { virtual ~D() {} }; :::::::::::::: main.C :::::::::::::: #include <a.h> #include <dlfcn.h> #include <iostream> using std::cout; using std::endl; extern "C" { typedef bool func1 (B *); typedef D * func2 (); } bool castInMain (B *b) { std::cout << "castInMain()\n"; return 0 != dynamic_cast <D *> (b); } int main () { void *liba = dlopen ("./liba.so", RTLD_NOW | RTLD_GLOBAL); if (!liba) { cout << dlerror () << endl; return 1; } func1 *castInDso = (func1 *) dlsym (liba, "castInDso"); if (!castInDso) { cout << dlerror () << endl; return 1; } func2 *DInDso = (func2 *) dlsym (liba, "DInDso"); if (!DInDso) { cout << dlerror () << endl; return 1; } { D d; cout << castInMain (&d) << endl; cout << castInDso (&d) << endl; } { D *d = DInDso(); cout << castInMain (d) << endl; cout << castInDso (d) << endl; } } :::::::::::::: Makefile :::::::::::::: t = liba.so test all: $t clean: rm -f $t core liba.so: a.C a.h g++ -I. -shared -o $@ a.C test: main.C a.h g++ -I. -L. main.C -o $@ -ldl
Fix: *** gcc-3.0.1/libstdc++-v3/libsupc++/typeinfo Wed Jul 11 12:37:58 2001 --- /net/rnd/gs/home/kainz/pub/gcc-3.0.1/libstdc++-v3/libsupc++/typeinfo Mon Sep 10 15:23:30 2001 *************** *** 43,54 **** class __class_type_info; } // namespace __cxxabiv1 ! #if !__GXX_WEAK__ ! // If weak symbols are not supported, typeinfo names are not merged. ! #define __GXX_MERGED_TYPEINFO_NAMES 0 #else ! // On platforms that support weak symbols, typeinfo names are merged. ! #define __GXX_MERGED_TYPEINFO_NAMES 1 #endif namespace std --- 43,65 ---- class __class_type_info; } // namespace __cxxabiv1 ! #if 0 ! ! #if !__GXX_WEAK__ ! // If weak symbols are not supported, typeinfo names are not merged. ! #define __GXX_MERGED_TYPEINFO_NAMES 0 ! #else ! // On platforms that support weak symbols, typeinfo names are merged. ! #define __GXX_MERGED_TYPEINFO_NAMES 1 ! #endif ! #else ! ! // Even if weak symbols are supported, typeinfo names are not ! // always merged. On Linux, dynamic shared objects opened with ! // dlopen() have their own, non-shared copies of typeinfo names. ! #define __GXX_MERGED_TYPEINFO_NAMES 0 ! #endif namespace std
Responsible-Changed-From-To: unassigned->nathan Responsible-Changed-Why: Investigating
State-Changed-From-To: open->analyzed State-Changed-Why: confirmed. I can reproduce this
From: nathan@gcc.gnu.org To: gcc-bugs@gcc.gnu.org, gcc-gnats@gcc.gnu.org, gcc-prs@gcc.gnu.org, hubbard@ilm.com, jyost@ilm.com, kainz@ilm.com, nathan@gcc.gnu.org, nobody@gcc.gnu.org Cc: Subject: Re: libstdc++/4993: dynamic_cast incorrectly returns 0 Date: 3 Dec 2001 23:10:30 -0000 Synopsis: dynamic_cast incorrectly returns 0 Responsible-Changed-From-To: unassigned->nathan Responsible-Changed-By: nathan Responsible-Changed-When: Mon Dec 3 15:10:30 2001 Responsible-Changed-Why: Investigating http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&pr=4993&database=gcc
From: nathan@gcc.gnu.org To: gcc-bugs@gcc.gnu.org, gcc-gnats@gcc.gnu.org, gcc-prs@gcc.gnu.org, hubbard@ilm.com, jyost@ilm.com, kainz@ilm.com, nathan@gcc.gnu.org Cc: Subject: Re: libstdc++/4993: dynamic_cast incorrectly returns 0 Date: 3 Dec 2001 23:42:08 -0000 Synopsis: dynamic_cast incorrectly returns 0 State-Changed-From-To: open->analyzed State-Changed-By: nathan State-Changed-When: Mon Dec 3 15:42:07 2001 State-Changed-Why: confirmed. I can reproduce this http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&pr=4993&database=gcc
State-Changed-From-To: analyzed->closed State-Changed-Why: User error. Not only must you specify RTDL_GLOBAL when loading the dso, you must export symbols from the main program. Do this by giving the -E (--export-dynamic) flag to the linker. (Remember to say -Wl,-E, as otherwise you'll get confused like I did for 30 seconds until you realise a naked -E means something else). Refer the ld's man page for the meaning of -E. I will prepare a FAQ patch describing this. I've also attached a sample program (taken from your bug report) which now prints the expected result.
From: Florian Kainz <kainz@ilm.com> To: nathan@gcc.gnu.org Cc: gcc-bugs@gcc.gnu.org, gcc-gnats@gcc.gnu.org, gcc-prs@gcc.gnu.org, hubbard@ilm.com, jyost@ilm.com, kainz@ilm.com Subject: Re: libstdc++/4993: dynamic_cast incorrectly returns 0 Date: Fri, 07 Dec 2001 16:12:05 -0800 Thank you for your help. We'll use RTLD_GLOBAL and -Wl,-E. Florian Kainz
From: nathan@gcc.gnu.org To: gcc-bugs@gcc.gnu.org, gcc-gnats@gcc.gnu.org, gcc-prs@gcc.gnu.org, hubbard@ilm.com, jyost@ilm.com, kainz@ilm.com, nathan@gcc.gnu.org Cc: Subject: Re: libstdc++/4993: dynamic_cast incorrectly returns 0 Date: 7 Dec 2001 21:50:05 -0000 Synopsis: dynamic_cast incorrectly returns 0 State-Changed-From-To: analyzed->closed State-Changed-By: nathan State-Changed-When: Fri Dec 7 13:50:04 2001 State-Changed-Why: User error. Not only must you specify RTDL_GLOBAL when loading the dso, you must export symbols from the main program. Do this by giving the -E (--export-dynamic) flag to the linker. (Remember to say -Wl,-E, as otherwise you'll get confused like I did for 30 seconds until you realise a naked -E means something else). Refer the ld's man page for the meaning of -E. I will prepare a FAQ patch describing this. I've also attached a sample program (taken from your bug report) which now prints the expected result. http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&pr=4993&database=gcc