If a polymorphic subclass is defined only in a header file, shared libraries built with -flto=thin give the vtable symbol LOCAL visibility. This means that there may be more than one vtable in a binary that uses this shared library. The dynamic_cast optimizations in llvm 17's libcxxapi (https://reviews.llvm.org/D138005) don't seem to expect that this can happen for final classes, causing dynamic_cast to incorrectly return nullptr.
To repro:
a.h
struct Foo {
virtual ~Foo();
};
struct Bar final : public Foo {
};
Foo* makeBar();
If a polymorphic subclass is defined only in a header file, shared libraries built with
-flto=thin
give the vtable symbol LOCAL visibility. This means that there may be more than one vtable in a binary that uses this shared library. The dynamic_cast optimizations in llvm 17's libcxxapi (https://reviews.llvm.org/D138005) don't seem to expect that this can happen for final classes, causing dynamic_cast to incorrectly return nullptr.To repro: a.h
a.cc
b.cc
Compile with
When run, the first dynamic_cast returns nullptr
Changing the final clang invocation to clang++-16 avoids the issue.
readelf shows that Bar's vtable gets LOCAL visibility (in both clang 16 and 17) when
-flto=thin
is used, but WEAK in the default caseI am using
Ubuntu clang version 17.0.4 (++20231025123955+afbe3549af4d-1~exp1~20231025124009.57)