Bug 4993 - dynamic_cast incorrectly returns 0
Summary: dynamic_cast incorrectly returns 0
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Nathan Sidwell
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2001-12-03 12:26 UTC by kainz
Modified: 2003-07-25 17:33 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
4993.tgz (1.00 KB, application/x-gzip )
2003-05-21 15:17 UTC, kainz
Details

Note You need to log in before you can comment on or make changes to this bug.
Description kainz 2001-12-03 12:26:01 UTC
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
Comment 1 kainz 2001-12-03 12:26:01 UTC
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
Comment 2 Nathan Sidwell 2001-12-03 15:10:30 UTC
Responsible-Changed-From-To: unassigned->nathan
Responsible-Changed-Why: Investigating
Comment 3 Nathan Sidwell 2001-12-03 15:42:07 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: confirmed. I can reproduce this
Comment 4 Nathan Sidwell 2001-12-03 23:10:30 UTC
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
Comment 5 Nathan Sidwell 2001-12-03 23:42:08 UTC
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
Comment 6 Nathan Sidwell 2001-12-07 13:50:04 UTC
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.
Comment 7 kainz 2001-12-07 16:12:05 UTC
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
Comment 8 Nathan Sidwell 2001-12-07 21:50:05 UTC
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