[Bug tree-optimization/99074] New: gcc 8 and above is crashing with dynamic_cast<>() on null pointer with optimization level -O1 and above

keith.halligan at microfocus dot com gcc-bugzilla@gcc.gnu.org
Thu Feb 11 16:34:23 GMT 2021


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


More information about the Gcc-bugs mailing list