https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128354

            Bug ID: 128354
           Summary: ICE in symtab_node::get_alias_target after
                    devirtualizing an explicit destructor call at -O1
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: ice-on-valid-code
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: yqtian668 at gmail dot com
  Target Milestone: ---
            Target: x86_64-pc-linux-gnu

At -O1, GCC aborts during the GIMPLE dse pass while compiling a valid explicit
virtual destructor call. FRE resolves the call to the complete-object
destructor of the allocated derived class; a later IPA mod-ref query crashes
while following that destructor's implicit alias.

Reproducer:

struct A;
void g(A &);
struct A {
  virtual ~A() {}
  virtual void f();
};
struct B : A {
  ~B() { h(); }
  void h() { g(*this); }
};
int main() {
  A *p = new B;
  p->~A();
  p = new A;
  p->~A();
}

Command:

g++ -O1 -c testcase.cpp

Compiler:

g++ (GCC) 17.0.0 20261101 (experimental)
GCC commit cf6e20578339f81bb1a029dedd2d3248337aabba
Target: x86_64-pc-linux-gnu

Actual behavior:

GCC terminates with an internal compiler error during the GIMPLE dse pass. The
first useful frames are:

internal compiler error: Segmentation fault
symtab_node::get_alias_target()
symtab_node::ultimate_alias_target_1(availability*, symtab_node*)
cgraph_node::ultimate_alias_target(availability*, symtab_node*)
get_modref_function_summary(cgraph_node*)
dse_optimize_call

-O1 -fno-tree-dse reaches the same failure through cddce. The testcase compiles
with -O0, -O2, -O3, -Os, -O1 -fno-tree-fre, or -O1 -fno-inline. GCC 8.5
compiles it; GCC 9.5 through 16.2 and current trunk terminate with an internal
compiler error.

Expected behavior:

GCC should compile the valid C++ translation unit without an internal compiler
error. With definitions of A::f and g supplied in another translation unit, the
program also runs without a diagnostic under ASan and UBSan at -O0; Clang trunk
compiles and runs the same program.

Technical details:

After FRE, the first destructor call in main becomes a direct reference to
B::~B()'s complete-object destructor, _ZN1BD1Ev. The callgraph records
_ZN1BD1Ev as a cpp_implicit_alias of the base-object destructor _ZN1BD2Ev. The
crash occurs when get_modref_function_summary follows the callee through
get_alias_target; the dump suggests that the alias node no longer has its
expected alias reference at that point.

Removing the second new A and p->~A() pair, or calling g(*this) directly from
B::~B() instead of through B::h(), avoids the failure.

Reply via email to