ASAN 检测到与动态加载库共享的 class vtable 的 ODR 违规
ASAN detects ODR violation of vtable of class which is shared with dynamically loaded library
我正在开发一个项目,该项目有一个“util”库,其中包含日志记录、断言处理等内容。它被编译成一个添加了 -fPIC
的静态库。我还有一个插件系统,其中的插件是在运行时通过 dlopen
加载的共享库。这些插件和主要可执行文件都使用静态 util 库。
问题:现在我在使用 ASAN 时收到 AddressSanitizer: odr-violation
错误。该问题 size=40 'vtable for StdStreamWriter'
报告了两次,其中 StdStreamWriter 是静态库内部使用的接口的实现。
我非常努力地在 MWE 中重现它:
- 创建一个公开一些函数的静态库
- 在 std::shared_ptr
中使用接口和实现
- 创建一个共享库link反对
- 针对静态库和
dlopen
共享库 创建可执行文件linking
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)
但是无论我怎么努力,MWE 都没有出现这个问题。
我将差异追溯到 nm -C liblib.so | grep vtable
中的不同结果:
- MWE(无 ODR 错误)显示
V vtable for Impl
- 实际程序显示
D vtable for StdStreamWriter
我猜错误源于 D
与 V
的差异,这导致 vtables 没有被合并。
这种差异从何而来?这是什么时候决定的?我将共享库的 link 命令精简为基本要素 (clang++-8 -shared -fsanitize=address,undefined -o <..> <all *.o and *.so>
),但仍然得到 D vtable
而不是 V vtable
.
我还能尝试什么来解决这个问题?
这很可能是由 known issue in Clang's implementation of Asan which causes it to detect false ODR violations for static data with vague linkage(通常是 class vtables 或 typeinfos)引起的。
作为解决方法,请尝试使用 -mllvm -asan-use-private-alias=1
进行编译,并可能在 运行 您的代码之前执行 export ASAN_OPTIONS=use_odr_indicator=1
。
如果这解决了您的问题,请post在上述问题中发表评论,以增加上游一劳永逸地解决问题的机会。
我正在开发一个项目,该项目有一个“util”库,其中包含日志记录、断言处理等内容。它被编译成一个添加了 -fPIC
的静态库。我还有一个插件系统,其中的插件是在运行时通过 dlopen
加载的共享库。这些插件和主要可执行文件都使用静态 util 库。
问题:现在我在使用 ASAN 时收到 AddressSanitizer: odr-violation
错误。该问题 size=40 'vtable for StdStreamWriter'
报告了两次,其中 StdStreamWriter 是静态库内部使用的接口的实现。
我非常努力地在 MWE 中重现它:
- 创建一个公开一些函数的静态库
- 在 std::shared_ptr 中使用接口和实现
- 创建一个共享库link反对
- 针对静态库和
dlopen
共享库 创建可执行文件linking
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)
但是无论我怎么努力,MWE 都没有出现这个问题。
我将差异追溯到 nm -C liblib.so | grep vtable
中的不同结果:
- MWE(无 ODR 错误)显示
V vtable for Impl
- 实际程序显示
D vtable for StdStreamWriter
我猜错误源于 D
与 V
的差异,这导致 vtables 没有被合并。
这种差异从何而来?这是什么时候决定的?我将共享库的 link 命令精简为基本要素 (clang++-8 -shared -fsanitize=address,undefined -o <..> <all *.o and *.so>
),但仍然得到 D vtable
而不是 V vtable
.
我还能尝试什么来解决这个问题?
这很可能是由 known issue in Clang's implementation of Asan which causes it to detect false ODR violations for static data with vague linkage(通常是 class vtables 或 typeinfos)引起的。
作为解决方法,请尝试使用 -mllvm -asan-use-private-alias=1
进行编译,并可能在 运行 您的代码之前执行 export ASAN_OPTIONS=use_odr_indicator=1
。
如果这解决了您的问题,请post在上述问题中发表评论,以增加上游一劳永逸地解决问题的机会。