On Aug 6, 2023, at 14:40, Christoph Moench-Tegeder <[email protected]> wrote:

> Hi,
> while updating our kicad port I'm facing major problems with
> dynamic_cast on FreeBSD 13.2/amd64 - issues are seen with both base
> clang and devel/llvm15, and I guess we're rather talking libc++ here.
> Specifically, dynamic_cast fails when casting from a base to a derived
> type ("downcast" as in C++ lingo?). I already know about "--export-dynamic"
> but that does not help here - and as far as I read other platform's
> build scripts, no other platform requires any kind of "special
> handling" for dynamic_cast to work - what am I holding wrong here,
> or what's missing from the picture?
> 
> But for the gory details: here's exhibit A, the code in question:
> https://gitlab.com/kicad/code/kicad/-/blob/7.0/include/settings/settings_manager.h?ref_type=heads#L110
> That m_settings is declared as
> std::vector<std::unique_ptr<JSON_SETTINGS>> m_settings;
> and contains objects of types derived from JSON_SETTINGS (there's
> the intermediate type APP_SETTINGS_BASE, and specific types like
> KICAD_SETTINGS etc.) The function GetAppSettings<KICAD_SETTING>() is
> called, so that the find_if() in there should return that one
> KICAD_SETTINGS object from m_settings as only that should
> satisfy dynamic_cast - but in fact, no object is found.
> That also happens if I unwind the find_if() and build a simple
> for-loop (as one did, back in the last millenium).
> 
> If I point gdb at that m_settings (with "set print object on" and
> "set print vtbl on"), I do find my KICAD_SETTINGS object smack
> in the middle of m_settings:
> 
> (gdb) print *(m_settings[5])
> $18 = (KICAD_SETTINGS) {<APP_SETTINGS_BASE> = {<JSON_SETTINGS> = {
>      _vptr$JSON_SETTINGS = 0xed1578 <vtable for KICAD_SETTINGS+16>,
> 
> so the type info isn't totally lost here.
> 
> When testing this, CXXFLAGS passed via cmake are rather minimal,
> like "-std=c++17 -O0 -fstack-protector-strong -fno-strict-aliasing
> -Wl,--export-dynamic" (and cmake sprinkles some "-g" and a few
> other standard flags into the mix), LDFLAGS ("CMAKE_...LINKER_FLAGS")
> are set up similarly) (I have some inkling that these cmakefiles
> in this project are not always very strict on compiling vs linking).
> 
> I had similar issues with dynamic_cast before, as witnessed here:
> https://cgit.freebsd.org/ports/tree/cad/kicad/files/patch-job_use_dynamic_cast_for_updating
> but now that I'm facing the current problem, I have a strong feeling
> that my diagnosis back than was rather bullshit.
> 
> Help?

May be the following type of thing from 

https://www.gnu.org/software/gcc/java/faq.html

might be relevant to your context? I can not
tell from the description. (A different ABI
could have differing details. But the below
could be at least suggestive of considerations.)



dynamic_cast, throw, typeid don't work with shared libraries

The new C++ ABI in the GCC 3.0 series uses address comparisons, rather than 
string compares, to determine type equality. This leads to better performance. 
Like other objects that have to be present in the final executable, these 
std::type_info objects have what is called vague linkage because they are not 
tightly bound to any one particular translation unit (object file). The 
compiler has to emit them in any translation unit that requires their presence, 
and then rely on the linking and loading process to make sure that only one of 
them is active in the final executable. With static linking all of these 
symbols are resolved at link time, but with dynamic linking, further resolution 
occurs at load time. You have to ensure that objects within a shared library 
are resolved against objects in the executable and other shared libraries.

    • For a program which is linked against a shared library, no additional 
precautions are needed.
    • You cannot create a shared library with the "-Bsymbolic" option, as that 
prevents the resolution described above.
    • If you use dlopen to explicitly load code from a shared library, you must 
do several things. First, export global symbols from the executable by linking 
it with the "-E" flag (you will have to specify this as "-Wl,-E" if you are 
invoking the linker in the usual manner from the compiler driver, g++). You 
must also make the external symbols in the loaded library available for 
subsequent libraries by providing the RTLD_GLOBAL flag to dlopen. The symbol 
resolution can be immediate or lazy.

Template instantiations are another, user visible, case of objects with vague 
linkage, which needs similar resolution. If you do not take the above 
precautions, you may discover that a template instantiation with the same 
argument list, but instantiated in multiple translation units, has several 
addresses, depending in which translation unit the address is taken. (This is 
not an exhaustive list of the kind of objects which have vague linkage and are 
expected to be resolved during linking & loading.)

If you are worried about different objects with the same name colliding during 
the linking or loading process, then you should use namespaces to disambiguate 
them. Giving distinct objects with global linkage the same name is a violation 
of the One Definition Rule (ODR) [basic.def.odr].

For more details about the way that GCC implements these and other C++ 
features, please read the C++ ABI specification. Note the std::type_info 
objects which must be resolved all begin with "_ZTS". Refer to ld's 
documentation for a description of the "-E" & "-Bsymbolic" flags.


===
Mark Millard
marklmi at yahoo.com


Reply via email to