ASAN detects ODR violation of vtable of class whic

2020-08-01 14:12发布

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?

1条回答
做自己的国王
2楼-- · 2020-08-01 14:35

This is most likely caused by a known issue in Clang's implementation of Asan which causes it to detect false ODR violations for static data with vague linkage (normally class vtables or typeinfos).

As a workaround, try compiling with -mllvm -asan-use-private-alias=1 and maybe doing export ASAN_OPTIONS=use_odr_indicator=1 before running your code.

If this fixes your problem, please post a comment in the aforementioned issue to increase the chance that it's fixed once and for all in upstream.

查看更多
登录 后发表回答