Bug 201784 - [libcxxrt] C++ dynamic_cast does not recognize same types across dynamically loaded modules when downcasting
Summary: [libcxxrt] C++ dynamic_cast does not recognize same types across dynamically ...
Status: Closed Works As Intended
Alias: None
Product: Base System
Classification: Unclassified
Component: standards (show other bugs)
Version: 10.2-STABLE
Hardware: Any Any
: --- Affects Only Me
Assignee: David Chisnall
Depends on:
Reported: 2015-07-23 10:40 UTC by Marcin Cieślak
Modified: 2015-08-10 17:17 UTC (History)
4 users (show)

See Also:

dynamic_cast testcase (shell archive) (4.76 KB, text/plain)
2015-07-23 10:40 UTC, Marcin Cieślak
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Marcin Cieślak 2015-07-23 10:40:53 UTC
Created attachment 159107 [details]
dynamic_cast testcase (shell archive)

dynamic_cast returns 0 when the (apparently same) type is known in the different runtime modules.

The attached test (just run "make all run" with BSD make or bmake on Linux) returns:

Parent::something() = 1
Child::something() = 2
library dynamic_cast<Child *>(Parent *) = 0x0
library dynamic_cast<Child *>(Child *) = 0x0
local dynamic_cast<Child *>(Parent *) = 0x0
local dynamic_cast<Child *>(Child *) = 0x7fffffffe580

When using libstdc++.so.6 from gcc48 or newer:

Parent::something() = 1
Child::something() = 2
library dynamic_cast<Child *>(Parent *) = (nil)
library dynamic_cast<Child *>(Child *) = 0x7fffaea254c0
local dynamic_cast<Child *>(Parent *) = (nil)
local dynamic_cast<Child *>(Child *) = 0x7fffaea254c0
Comment 1 Marcin Cieślak 2015-07-23 11:05:34 UTC
Original bug report:

Comment 2 Marcin Cieślak 2015-07-23 11:06:11 UTC
Original bug report: https://github.com/marekjm/viuavm/issues/70
Comment 3 David Chisnall freebsd_committer 2015-07-23 11:10:57 UTC
This is a known issue (I can't find the closed bug report for it at the moment).  If you don't link with -Wl,-export-dynamic, then the RTTI symbols will not be merged.  This then means that the pointer comparison in libcxxrt will fail.  The work-around that libsupc++ implements replaces the pointer comparison with string comparison.  This adds a noticeable performance hit in all dynamic_casts.  We decided not to impose a performance hit on all C++ programs just to benefit people who can pass different linker flags to avoid a bug.
Comment 4 Marcin Cieślak 2015-07-23 12:10:43 UTC
Thanks, I was searching for it in the Bugzilla and could not find one.

The rationale seems very reasonable to me. By the way I have just discovered -Wl,--dynamic-list-cpp-typeinfo which also does the job.
Comment 5 David Chisnall freebsd_committer 2015-07-23 12:30:46 UTC
I wonder if we should modify the clang driver so that it always passes --dynamic-list-cpp-typeinfo by default when linking C++.  Are there any down sides to this?
Comment 6 Marcin Cieślak 2015-07-23 12:37:30 UTC
By the way, our <bsd.lib.mk> always uses ${CC} when linking shared library (and it's silenced with @). Is this okay for C++ libs?
Comment 7 David Chisnall freebsd_committer 2015-07-23 12:43:55 UTC
Hmm, possibly for the specific case of the base system, where we explicitly pass -lc++ and so on.  It's generally a very bad idea though.
Comment 8 Dimitry Andric freebsd_committer 2015-07-23 12:57:40 UTC
(In reply to Marcin Cieślak from comment #6)
> By the way, our <bsd.lib.mk> always uses ${CC} when linking shared library
> (and it's silenced with @). Is this okay for C++ libs?

Not if you specify the lib using LIB_CXX, like in the libatf-c++ Makefile:

LIB_CXX= atf-c++

We used to do a 'deep' comparison of the typeinfo earlier, but only in head from r256642 onwards, and we eventually reverted it in r278010.  As Jörg Sonnenberger noted in a private mail conversation:

"... there are three different problematic situations:

(1) A type is used in the main program and it is linked without

(2) A type is used by two different DSOs and both are loaded with

(3) Two independent types of the same name are defined in two different

The hack makes the first two work to a degree and fails misserable on
the last. IMO (2) and (3) should be considered the same and (1) is just
a bug."

(N.B.: with 'the hack' he meant doing the deep comparison.)
Comment 9 Marcin Cieślak 2015-07-23 13:03:56 UTC
oh, ok. LIB_CXX is not there on my oldish -CURRENT, it got in there in March 2015.