I'm working on a project which has a "util" library containing stuff like logging, assertion handling etc. This is compiled into a static library with -fPIC
added. I also have a plugin system, where the plugins are shared libraries loaded at runtime via dlopen
. Those plugins and the main executable both use the static util library.
The problem: Now I'm getting AddressSanitizer: odr-violation
errors when using ASAN. The issue is size=40 'vtable for StdStreamWriter'
reported twice where StdStreamWriter is an implementation of an interface used internally in the static library.
I tried really hard to reproduce this in a MWE:
- Create a static library exposing some function
- Inside that use an interface and implementation in a std::shared_ptr
- create a shared library linking against that
- create an executable linking against the static lib and
dlopen
the shared library
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(proj)
set(sanitizer_flags "-fsanitize=address,undefined -fno-omit-frame-pointer")
string(APPEND CMAKE_CXX_FLAGS " ${sanitizer_flags}")
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${sanitizer_flags}")
string(APPEND CMAKE_MODULE_LINKER_FLAGS " ${sanitizer_flags}")
add_library(foo STATIC foo.cpp)
target_compile_features(foo PUBLIC cxx_std_14)
set_target_properties(foo PROPERTIES CXX_EXTENSIONS OFF POSITION_INDEPENDENT_CODE ON)
add_library(lib SHARED lib.cpp)
target_link_libraries(lib foo)
add_executable(main main.cpp)
target_link_libraries(main foo dl)
However the issue does not occur in the MWE no matter how hard I try.
I traced the difference down to differing results in nm -C liblib.so | grep vtable
:
- The MWE (no ODR error) shows
V vtable for Impl
- The acutal program shows
D vtable for StdStreamWriter
I guess the error stems from the difference D
vs V
which results in the vtables not being merged.
Where does this difference come from? When is this decided? I stripped down the link command for the shared library to the bare essentials (clang++-8 -shared -fsanitize=address,undefined -o <..> <all *.o and *.so>
) but still get the D vtable
instead of V vtable
.
What else can I try to fix this?