https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99074
Bug ID: 99074 Summary: gcc 8 and above is crashing with dynamic_cast<>() on null pointer with optimization level -O1 and above Product: gcc Version: 8.3.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: keith.halligan at microfocus dot com Target Milestone: --- Created attachment 50169 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=50169&action=edit comparison of the disassembly at -O0, O1, and -O2 levels When compiling the small snippet below with g++/gcc v8.3.1 the dynamic_cast<>() operator with a null pointer argument will result in a segmentation fault at optimizations levels from -O1 and above. I am running this on both RHEL 8 and SLES 15, in addition I installed gcc-9 and gcc-10 toolchain packages, and the crashes were noticed on these newer compilers as well. I've also tested the code on RHEL 5 and 7 with gcc 4.1 and 4.8, and there's no crash at any optimization levels I've attached a file showing the difference in disassembly between -O0 and -O1, it looks at lower levels the call to dynamic_cast is bypassed under certain conditions, that doesn't happen at -O1 and above. The code was compiled with: g++ -Wall -m32 -O2 -o test_dyn_cast test_dyn_cast.cpp -v -save-temps ===== // file: test_dyn_cast.cpp // #include <cstdio> class Base { public: virtual ~Base() {} virtual void op() = 0; }; class Object: public virtual Base { }; class AbstractBase : public virtual Base { public: Object* _to_object() { return dynamic_cast<Object*>(this); } }; class MyAbstractClass : public virtual AbstractBase { public: static MyAbstractClass* _nil() { return 0; } }; int main(void) { MyAbstractClass *my_abs_type = MyAbstractClass::_nil(); AbstractBase *abs_base = my_abs_type; Object *obj = abs_base->_to_object(); printf("object is: %p\n", obj); return 0; } ====== $ g++ -Wall -m32 -O2 -o test_dyn_cast test_dyn_cast.cpp -v -save-temps Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/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=/usr --mandir=/usr/share/man --infodir=/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 --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --disable-libmpx --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux Thread model: posix gcc version 8.3.1 20191121 (Red Hat 8.3.1-5) (GCC) COLLECT_GCC_OPTIONS='-Wall' '-m32' '-O2' '-o' 'test_dyn_cast' '-v' '-save-temps' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-redhat-linux/8/cc1plus -E -quiet -v -imultilib 32 -D_GNU_SOURCE test_dyn_cast.cpp -m32 -mtune=generic -march=x86-64 -Wall -O2 -fpch-preprocess -o test_dyn_cast.ii ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/8/include-fixed" ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include" #include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux/32 /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward /usr/lib/gcc/x86_64-redhat-linux/8/include /usr/local/include /usr/include End of search list. COLLECT_GCC_OPTIONS='-Wall' '-m32' '-O2' '-o' 'test_dyn_cast' '-v' '-save-temps' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-redhat-linux/8/cc1plus -fpreprocessed test_dyn_cast.ii -quiet -dumpbase test_dyn_cast.cpp -m32 -mtune=generic -march=x86-64 -auxbase test_dyn_cast -O2 -Wall -version -o test_dyn_cast.s GNU C++14 (GCC) version 8.3.1 20191121 (Red Hat 8.3.1-5) (x86_64-redhat-linux) compiled by GNU C version 8.3.1 20191121 (Red Hat 8.3.1-5), GMP version 6.1.2, MPFR version 3.1.6-p2, MPC version 1.0.2, isl version isl-0.16.1-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 GNU C++14 (GCC) version 8.3.1 20191121 (Red Hat 8.3.1-5) (x86_64-redhat-linux) compiled by GNU C version 8.3.1 20191121 (Red Hat 8.3.1-5), GMP version 6.1.2, MPFR version 3.1.6-p2, MPC version 1.0.2, isl version isl-0.16.1-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: d41110238f51283cc9cdc51fe0924921 COLLECT_GCC_OPTIONS='-Wall' '-m32' '-O2' '-o' 'test_dyn_cast' '-v' '-save-temps' '-shared-libgcc' '-mtune=generic' '-march=x86-64' as -v --32 -o test_dyn_cast.o test_dyn_cast.s GNU assembler version 2.30 (x86_64-redhat-linux) using BFD version version 2.30-73.el8 COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/8/:/usr/libexec/gcc/x86_64-redhat-linux/8/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/8/:/usr/lib/gcc/x86_64-redhat-linux/ LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/8/32/:/usr/lib/gcc/x86_64-redhat-linux/8/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-redhat-linux/8/:/usr/lib/gcc/x86_64-redhat-linux/8/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-Wall' '-m32' '-O2' '-o' 'test_dyn_cast' '-v' '-save-temps' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-redhat-linux/8/collect2 -plugin /usr/libexec/gcc/x86_64-redhat-linux/8/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper -plugin-opt=-fresolution=test_dyn_cast.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test_dyn_cast /usr/lib/gcc/x86_64-redhat-linux/8/../../../../lib/crt1.o /usr/lib/gcc/x86_64-redhat-linux/8/../../../../lib/crti.o /usr/lib/gcc/x86_64-redhat-linux/8/32/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/8/32 -L/usr/lib/gcc/x86_64-redhat-linux/8/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-redhat-linux/8 -L/usr/lib/gcc/x86_64-redhat-linux/8/../../.. test_dyn_cast.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-redhat-linux/8/32/crtend.o /usr/lib/gcc/x86_64-redhat-linux/8/../../../../lib/crtn.o COLLECT_GCC_OPTIONS='-Wall' '-m32' '-O2' '-o' 'test_dyn_cast' '-v' '-save-temps' '-shared-libgcc' '-mtune=generic' '-march=x86-64' ======= $ ./test_dyn_cast Segmentation fault (core dumped) ======= $ gdb ./test_dyn_cast GNU gdb (GDB) Red Hat Enterprise Linux 8.2-11.el8 Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-redhat-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./test_dyn_cast...(no debugging symbols found)...done. (gdb) run Starting program: /x1/users/keithh/test_dyn_cast Program received signal SIGSEGV, Segmentation fault. 0xf7e9a023 in __cxxabiv1::__dynamic_cast (src_ptr=0x0, src_type=0x80486ec <typeinfo for AbstractBase>, dst_type=0x80486c4 <typeinfo for Object>, src2dst=-2) at ../../../../libstdc++-v3/libsupc++/dyncast.cc:50 50 const void *vtable = *static_cast <const void *const *> (src_ptr); (gdb) bt #0 0xf7e9a023 in __cxxabiv1::__dynamic_cast (src_ptr=0x0, src_type=0x80486ec <typeinfo for AbstractBase>, dst_type=0x80486c4 <typeinfo for Object>, src2dst=-2) at ../../../../libstdc++-v3/libsupc++/dyncast.cc:50 #1 0x080484b4 in main () (gdb) quit