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
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-07-23 10:40 UTC by Marcin Cieślak
Modified: 2015-08-10 17:17 UTC (History)
4 users (show)

See Also:


Attachments
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:

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=201784
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 freebsd_triage 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 freebsd_triage 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 freebsd_triage 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 freebsd_triage 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
-rdynamic.

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

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

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.