Skip to content

Instantly share code, notes, and snippets.

@paulgessinger
Last active November 29, 2024 17:14
Show Gist options
  • Save paulgessinger/2c1d2abdeb322072c507878ab5833728 to your computer and use it in GitHub Desktop.
Save paulgessinger/2c1d2abdeb322072c507878ab5833728 to your computer and use it in GitHub Desktop.
Clang typeinfo / dynamic_cast issue

Clang dynamic_cast fails across shared library boundary

A derived polymorphic template class that is final which is created in a shared library cannot be dynamic_cast to its base class in another TU.

$ cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
$ cmake --build build && build/DowncastRepro
[4/4] Linking CXX executable DowncastRepro
dynamic_cast non-final: 0x600001164030
dynamic_cast final:     0x0
dynamic_cast final loc: 0x600003aa8000
#include "class.hpp"
std::unique_ptr<Base> create() { return std::make_unique<Derived<int>>(); }
std::unique_ptr<Base> createFinal() {
return std::make_unique<DerivedFinal<int>>();
}
const std::type_info &info() { return typeid(Derived<int>); }
const std::type_info &infoFinal() { return typeid(DerivedFinal<int>); }
#pragma once
#include <memory>
#include <typeinfo>
struct Base {
virtual ~Base() = default;
};
template <typename T> struct DerivedFinal final : public Base {};
template <typename T> struct Derived : public Base {};
std::unique_ptr<Base> create();
std::unique_ptr<Base> createFinal();
cmake_minimum_required(VERSION 3.14)
project(DowncastRepro LANGUAGES CXX)
add_library(Foo SHARED class.cpp)
target_include_directories(Foo PUBLIC .)
target_compile_features(Foo PUBLIC cxx_std_20)
add_executable(DowncastRepro main.cpp)
target_link_libraries(DowncastRepro PRIVATE Foo)
#include <iostream>
#include "class.hpp"
int main() {
auto base = create();
auto *derived = dynamic_cast<Derived<int> *>(base.get());
std::cout << "dynamic_cast non-final: " << derived << std::endl;
base = createFinal();
auto *derivedFinal = dynamic_cast<DerivedFinal<int> *>(base.get());
std::cout << "dynamic_cast final: " << derivedFinal << std::endl;
base = std::make_unique<DerivedFinal<int>>();
auto *derivedFinalLocal = dynamic_cast<DerivedFinal<int> *>(base.get());
std::cout << "dynamic_cast final loc: " << derivedFinalLocal << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment