GCC UBSAN与visibility、RTTI相关技术问题咨询
GCC UBSAN与visibility属性相关问题
问题背景
我遇到了GCC中Undefined Behavior Sanitizer(UBSAN)与visibility属性相关的问题,无法理解背后原因。根据GCC Bugzilla#80963的说明,示例代码因visibility设置存在未定义行为。我分别在Ubuntu(GCC 13.1.0)和RHEL8(gcc-toolset-13,GCC 13.1.1)环境下运行测试脚本,发现仅在RHEL环境中,且编译main.cpp未添加-fno-rtti参数时,UBSAN才检测到未定义行为。
测试脚本
$ cat ubsan_example.sh #!/bin/bash set -ex cat << EOF | struct Archive { virtual void foo() = 0; }; __attribute__((visibility("default"))) Archive *factory(); EOF awk '{print}' > lib.h cat << EOF | #include "lib.h" struct ArchiveImpl : Archive { void foo(); }; void ArchiveImpl::foo() {} Archive *factory() { return new ArchiveImpl; } EOF awk '{print}' > libimpl.cpp cat << EOF | #include "lib.h" int main(void) { factory()->foo(); } EOF awk '{print}' > main.cpp echo "Compiler information" g++ -v g++ -fPIC -o libimpl.so -shared libimpl.cpp -fvisibility=hidden -Wall -fsanitize=undefined -lubsan g++ -o main main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -lubsan echo "Running main" ./main g++ -o main-nortti main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -fno-rtti -lubsan echo "Running main-nortti" ./main-nortti
测试结果
Ubuntu环境输出
$ ./ubsan_example.sh + cat + awk '{print}' + cat + awk '{print}' + cat + awk '{print}' + echo 'Compiler information' Compiler information + g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.1.0-2ubuntu2~23.04' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2,rust --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-aYYs71/gcc-13-13.1.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-aYYs71/gcc-13-13.1.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.1.0 (Ubuntu 13.1.0-2ubuntu2~23.04) + g++ -fPIC -o libimpl.so -shared libimpl.cpp -fvisibility=hidden -Wall -fsanitize=undefined -lubsan + g++ -o main main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -lubsan + echo 'Running main' Running main + ./main + g++ -o main-nortti main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -fno-rtti -lubsan + echo 'Running main-nortti' Running main-nortti + ./main-nortti
RHEL8环境输出
$ ./ubsan_example.sh + cat + awk '{print}' + cat + awk '{print}' + cat + awk '{print}' + echo 'Compiler information' Compiler information + g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/opt/rh/gcc-toolset-13/root/usr/libexec/gcc/x86_64-redhat-linux/13/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/opt/rh/gcc-toolset-13/root/usr --mandir=/opt/rh/gcc-toolset-13/root/usr/share/man --infodir=/opt/rh/gcc-toolset-13/root/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --enable-libstdcxx-backtrace --with-libstdcxx-zoneinfo=/opt/rh/gcc-toolset-13/root/usr/share/zoneinfo --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl=/builddir/build/BUILD/gcc-13.1.1-20230614/obj-x86_64-redhat-linux/isl-install --enable-offload-targets=nvptx-none --without-cuda-driver --enable-offload-defaulted --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.1.1 20230614 (Red Hat 13.1.1-4) (GCC) + g++ -fPIC -o libimpl.so -shared libimpl.cpp -fvisibility=hidden -Wall -fsanitize=undefined -lubsan + g++ -o main main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -lubsan + echo 'Running main' Running main + ./main main.cpp:3:23: runtime error: member call on address 0x000000550eb0 which does not point to an object of type 'Archive' 0x000000550eb0: note: object is of type 'ArchiveImpl' 00 00 00 00 80 8d f0 13 b9 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 ^~~~~~~~~~~~~~~~~~~~~~~ vptr for 'ArchiveImpl' + g++ -o main-nortti main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -fno-rtti -lubsan + echo 'Running main-nortti' Running main-nortti + ./main-nortti
核心疑问
- 该情况是否确实属于未定义行为?
- 为何仅RHEL版本的GCC会触发运行时错误?是补丁、默认参数差异还是版本(13.1.0 vs 13.1.1)导致?
- 为何编译main.cpp时添加
-fno-rtti参数后未检测到未定义行为?
测试代码与编译命令
lib.h
struct Archive { virtual void foo() = 0; }; __attribute__((visibility("default"))) Archive *factory();
libimpl.cpp
#include "lib.h" struct ArchiveImpl : Archive { void foo(); }; void ArchiveImpl::foo() {} Archive *factory() { return new ArchiveImpl; }
main.cpp
#include "lib.h" int main(void) { factory()->foo(); }
编译命令
g++ -fPIC -o libimpl.so -shared libimpl.cpp -fvisibility=hidden -Wall -fsanitize=undefined -lubsan g++ -o main main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -lubsan # 编译main.cpp时禁用RTTI g++ -o main-nortti main.cpp ./libimpl.so -fvisibility=hidden -Wall -fsanitize=undefined -fno-rtti -lubsan
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

