Bug 60419 - [4.8 Regression] ICE Segmentation fault
Summary: [4.8 Regression] ICE Segmentation fault
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.8.3
: P1 normal
Target Milestone: 4.8.3
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-04 23:04 UTC by Matthias Klose
Modified: 2014-03-26 13:50 UTC (History)
4 users (show)

See Also:
Host:
Target: arm-linxux-gnueabihf powerpc-linux-gnu powepc64le-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2014-03-10 00:00:00


Attachments
preprocessed source (472.78 KB, application/x-xz)
2014-03-04 23:04 UTC, Matthias Klose
Details
preprocessed source (armv7) (466.15 KB, application/x-xz)
2014-03-05 08:34 UTC, Matthias Klose
Details
pr60419.C (25.99 KB, text/plain)
2014-03-09 21:41 UTC, Jakub Jelinek
Details
reduced testcase (792 bytes, text/plain)
2014-03-18 17:20 UTC, Markus Trippelsdorf
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Klose 2014-03-04 23:04:35 UTC
Created attachment 32264 [details]
preprocessed source

see on
https://bugs.launchpad.net/ubuntu/+source/mrpt/+bug/1286343
https://bugzilla.redhat.com/show_bug.cgi?id=1007586

seen on armv7, powerpc, ppc64el. lowering the optimization works around it

$ g++ -std=c++11 -c -O3  -g CMetricMapBuilderICP.ii
/root/mrpt-1.0.2/libs/slam/src/slam/CMetricMapBuilderICP.cpp:629:1: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.

Program received signal SIGSEGV, Segmentation fault.
0x0000000010ae517c in ?? ()
(gdb) bt
#0  0x0000000010ae517c in ?? ()
#1  0x000000001056a0c0 in execute_one_pass(opt_pass*) ()
#2  0x000000001056ad88 in execute_ipa_pass_list(opt_pass*) ()
#3  0x000000001032ce28 in compile() ()
#4  0x000000001032d6cc in finalize_compilation_unit() ()
#5  0x000000001019017c in cp_write_global_declarations() ()
#6  0x000000001062b370 in ?? ()
#7  0x000000001062dafc in toplev_main(int, char**) ()
#8  0x000000001010ea88 in main ()
Comment 1 Yury Gribov 2014-03-05 05:09:11 UTC
Attached code seems to be Power-specific:
 ...
 /usr/include/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h:483:56: error: ‘__builtin_vec_sld’ was not declared in this scope
Comment 2 Matthias Klose 2014-03-05 05:42:28 UTC
yes, the first attachment is for powepc64le-linux-gnu
Comment 3 Matthias Klose 2014-03-05 08:34:14 UTC
Created attachment 32265 [details]
preprocessed source (armv7)
Comment 4 Yury Gribov 2014-03-05 09:06:16 UTC
This might have been fixed in trunk already, at least I can't repro for arm-v7a15. My fresh gcc is configured with
 ~/src/gcc-master/configure --build=x86_64-pc-linux-gnu --host=x86_64-pc-linux-gnu --target=arm-v7a15-linux-gnueabi --prefix=/home/ygribov/install/gcc-master-arm-full --with-sysroot=/home/ygribov/install/gcc-master-arm-full/arm-v7a15-linux-gnueabi/sys-root/ --disable-libmudflap --disable-libssp --disable-nls --disable-libstdcxx-pch --with-interwork --with-mode=arm --with-fpu=vfpv3 --with-cpu=cortex-a15 --with-tune=cortex-a15 --with-float=softfp --enable-libgomp --enable-poison-system-directories --enable-long-long --enable-threads --enable-languages=c,c++ --enable-shared --with-gnu-as --with-gnu-ld --with-build-time-tools=/home/ygribov/install/gcc-master-arm-full --enable-checking CFLAGS='-g -O0' CXXFLAGS='-g -O0'
Comment 5 Jakub Jelinek 2014-03-09 21:41:23 UTC
Created attachment 32321 [details]
pr60419.C

This is quite impossible to reduce, at least after 4 days of attempting to delta/creduce reduce this I got only to 132KB.
Compile with -m64 -O3 -std=c++11.
Anyway, it is reduced enough that it compiles (and ICEs in a different place) with x86_64-linux cc1plus, so also shows a bug in slsr, with -m64 -O3 -std=c++11 -fno-tree-slsr it compiles with x86_64 target though and thus I can't bisect this on x86_64.
Comment 6 Jakub Jelinek 2014-03-10 09:02:12 UTC
The slsr issue is just a pilot error, I've mistakenly used ~ r205NNN compiler in that case, so it looks like an already fixed issue.

Anyway, the ICE on ppc64 with the reduced testcase started with r208184 (thus I wonder about the 4.8 regression status), the problem is that
getMeanVal function (method?) calls
_ZThn8_NK4mrpt5utils16CPosePDFGaussian7getMeanERNS_5poses7CPose2DE
thunk that has NULL node->callee (without -fPIC it ICEs in one spot, with -fPIC in another one).

node->callees is set to non-NULL in:
#0  cgraph_create_edge (caller=<cgraph_node* 0x7ffff0f32148 "_ZThn8_NK4mrpt5utils16CPosePDFGaussian7getMeanERNS_5poses7CPose2DE">, 
    callee=<cgraph_node* 0x7ffff0f32000 "*.LTHUNK0">, call_stmt=<gimple 0x0>, count=0, freq=1000) at ../../gcc/cgraph.c:927
#1  0x00000000008ffe81 in analyze_function (
    node=<cgraph_node* 0x7ffff0f32148 "_ZThn8_NK4mrpt5utils16CPosePDFGaussian7getMeanERNS_5poses7CPose2DE">) at ../../gcc/cgraphunit.c:611
#2  0x00000000009010b4 in analyze_functions () at ../../gcc/cgraphunit.c:1017
#3  0x0000000000904979 in finalize_compilation_unit () at ../../gcc/cgraphunit.c:2320
#4  0x000000000068b61d in cp_write_global_declarations () at ../../gcc/cp/decl2.c:4612
#5  0x0000000000d0ee72 in compile_file () at ../../gcc/toplev.c:562
#6  0x0000000000d11015 in do_compile () at ../../gcc/toplev.c:1914
#7  0x0000000000d11180 in toplev_main (argc=8, argv=0x7fffffffe358) at ../../gcc/toplev.c:1990
#8  0x00000000012c0464 in main (argc=8, argv=0x7fffffffe358) at ../../gcc/main.c:36

and cleared again in:
#0  cgraph_node_remove_callees (node=<cgraph_node* 0x7ffff0f32148 "_ZThn8_NK4mrpt5utils16CPosePDFGaussian7getMeanERNS_5poses7CPose2DE">)
    at ../../gcc/cgraph.c:1617
#1  0x0000000000b2dc63 in symtab_remove_unreachable_nodes (before_inlining_p=false, file=0x0) at ../../gcc/ipa.c:493
#2  0x000000000124c93f in ipa_inline () at ../../gcc/ipa-inline.c:2060
#3  0x000000000124d385 in (anonymous namespace)::pass_ipa_inline::execute (this=0x1c73710) at ../../gcc/ipa-inline.c:2412
#4  0x0000000000c299d6 in execute_one_pass (pass=<opt_pass* 0x1c73710 "inline"(53)>) at ../../gcc/passes.c:2229
#5  0x0000000000c2a71b in execute_ipa_pass_list (pass=<opt_pass* 0x1c73710 "inline"(53)>) at ../../gcc/passes.c:2607
#6  0x00000000009042ad in ipa_passes () at ../../gcc/cgraphunit.c:2084
#7  0x000000000090455e in compile () at ../../gcc/cgraphunit.c:2174
#8  0x0000000000904988 in finalize_compilation_unit () at ../../gcc/cgraphunit.c:2329
#9  0x000000000068b61d in cp_write_global_declarations () at ../../gcc/cp/decl2.c:4612
#10 0x0000000000d0ee72 in compile_file () at ../../gcc/toplev.c:562
#11 0x0000000000d11015 in do_compile () at ../../gcc/toplev.c:1914
#12 0x0000000000d11180 in toplev_main (argc=8, argv=0x7fffffffe358) at ../../gcc/toplev.c:1990
#13 0x00000000012c0464 in main (argc=8, argv=0x7fffffffe358) at ../../gcc/main.c:36

At that point the thunk apparently has no callers.  But somewhat later it gains one:
#0  cgraph_set_edge_callee (e=0x7fffef50a8f0, 
    n=<cgraph_node* 0x7ffff0f32148 "_ZThn8_NK4mrpt5utils16CPosePDFGaussian7getMeanERNS_5poses7CPose2DE">) at ../../gcc/cgraph.c:1080
#1  0x00000000008f74a8 in cgraph_make_edge_direct (edge=0x7fffef50a8f0, 
    callee=<cgraph_node* 0x7ffff0f32148 "_ZThn8_NK4mrpt5utils16CPosePDFGaussian7getMeanERNS_5poses7CPose2DE">) at ../../gcc/cgraph.c:1313
#2  0x0000000000b1f7ae in ipa_make_edge_direct_to_target (ie=0x7fffef50a8f0, 
    target=<function_decl 0x7ffff0fc5a00 _ZThn8_NK4mrpt5utils16CPosePDFGaussian7getMeanERNS_5poses7CPose2DE>) at ../../gcc/ipa-prop.c:2551
#3  0x0000000000b20091 in try_make_edge_direct_virtual_call (ie=0x7fffef50a8f0, jfunc=0x7ffff085b078, new_root_info=0x1e4cce0)
    at ../../gcc/ipa-prop.c:2799
#4  0x0000000000b201e2 in update_indirect_edges_after_inlining (cs=0x7fffef9baf08, node=<cgraph_node* 0x7ffff0ad58f8 "getMeanVal">, new_edges=0x0)
    at ../../gcc/ipa-prop.c:2852
#5  0x0000000000b20476 in propagate_info_to_inlined_callees (cs=0x7fffef9baf08, node=<cgraph_node* 0x7ffff0ad58f8 "getMeanVal">, new_edges=0x0)
    at ../../gcc/ipa-prop.c:2924
#6  0x0000000000b20c3d in ipa_propagate_indirect_call_infos (cs=0x7fffef9baf08, new_edges=0x0) at ../../gcc/ipa-prop.c:3086
#7  0x000000000124e183 in inline_call (e=0x7fffef9baf08, update_original=true, new_edges=0x0, overall_size=0x0, update_overall_summary=true)
    at ../../gcc/ipa-inline-transform.c:277
#8  0x000000000124c6da in inline_to_all_callers (node=<cgraph_node* 0x7ffff0ad58f8 "getMeanVal">, data=0x7fffffffe024)
    at ../../gcc/ipa-inline.c:1987
#9  0x00000000008f9a18 in cgraph_for_node_and_aliases (node=<cgraph_node* 0x7ffff0ad58f8 "getMeanVal">, callback=
    0x124c5f5 <inline_to_all_callers(cgraph_node*, void*)>, data=0x7fffffffe024, include_overwritable=true) at ../../gcc/cgraph.c:2212
#10 0x000000000124cacc in ipa_inline () at ../../gcc/ipa-inline.c:2118
#11 0x000000000124d385 in (anonymous namespace)::pass_ipa_inline::execute (this=0x1c73710) at ../../gcc/ipa-inline.c:2412
#12 0x0000000000c299d6 in execute_one_pass (pass=<opt_pass* 0x1c73710 "inline"(53)>) at ../../gcc/passes.c:2229
#13 0x0000000000c2a71b in execute_ipa_pass_list (pass=<opt_pass* 0x1c73710 "inline"(53)>) at ../../gcc/passes.c:2607
#14 0x00000000009042ad in ipa_passes () at ../../gcc/cgraphunit.c:2084
#15 0x000000000090455e in compile () at ../../gcc/cgraphunit.c:2174
#16 0x0000000000904988 in finalize_compilation_unit () at ../../gcc/cgraphunit.c:2329
#17 0x000000000068b61d in cp_write_global_declarations () at ../../gcc/cp/decl2.c:4612
#18 0x0000000000d0ee72 in compile_file () at ../../gcc/toplev.c:562
#19 0x0000000000d11015 in do_compile () at ../../gcc/toplev.c:1914
#20 0x0000000000d11180 in toplev_main (argc=8, argv=0x7fffffffe358) at ../../gcc/toplev.c:1990
#21 0x00000000012c0464 in main (argc=8, argv=0x7fffffffe358) at ../../gcc/main.c:36
Comment 7 Jakub Jelinek 2014-03-12 16:24:08 UTC
Honza or Martin, can you please have a look?  The #c5 testcase should be reproduceable with a cross to powerpc64-linux.
Comment 8 Jakub Jelinek 2014-03-18 10:59:26 UTC
FYI, since r208573 the reduced ppc64 testcase no longer reproduces, but the #c0 still does.
Comment 9 Markus Trippelsdorf 2014-03-18 17:20:41 UTC
Created attachment 32382 [details]
reduced testcase

Here's a reduced testcase that segfaults also on x86_64.

markus@x4 tmp % g++ -std=c++11 -c -O2 -c test.ii 
ASAN:SIGSEGV
=================================================================
==17160==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010 (pc 0x000000d9b9b7 sp 0x7fff7ac203c0 bp 0x0fffef5840a0 T0)
    #0 0xd9b9b6 in cgraph_function_node(cgraph_node*, availability*) ../../gcc/gcc/cgraph.c:2966
    #1 0x25e6923 in propagate_pure_const ../../gcc/gcc/ipa-pure-const.c:1185
    #2 0x25e6923 in propagate ../../gcc/gcc/ipa-pure-const.c:1483
    #3 0x25e6923 in execute ../../gcc/gcc/ipa-pure-const.c:1536
    #4 0x14b93cd in execute_one_pass(opt_pass*) ../../gcc/gcc/passes.c:2229
    #5 0x14badd0 in execute_ipa_pass_list(opt_pass*) ../../gcc/gcc/passes.c:2607
    #6 0xdb2bb1 in ipa_passes ../../gcc/gcc/cgraphunit.c:2084
    #7 0xdb2bb1 in compile() ../../gcc/gcc/cgraphunit.c:2174
    #8 0xdb484a in finalize_compilation_unit() ../../gcc/gcc/cgraphunit.c:2329
    #9 0x84561a in cp_write_global_declarations() ../../gcc/gcc/cp/decl2.c:4610
    #10 0x16aa252 in compile_file ../../gcc/gcc/toplev.c:562
    #11 0x16af0db in do_compile ../../gcc/gcc/toplev.c:1914
    #12 0x16af0db in toplev_main(int, char**) ../../gcc/gcc/toplev.c:1990
    #13 0x7ff8fae69faf in __libc_start_main (/lib/libc.so.6+0x1ffaf)
    #14 0x5d9460 (/var/tmp/gcc_sani/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/4.9.0/cc1plus+0x5d9460)
Comment 10 Markus Trippelsdorf 2014-03-18 17:37:20 UTC
A bit more reduced:

markus@x4 tmp % cat test.ii
namespace poses
{
}
namespace utils
{
using namespace poses;
}
namespace poses
{
class J
{
public:
  J ();
  virtual void m_fn1 (int &p1, int);
};
class I : utils::J
{
};
class D
{
public:
  virtual void m_fn1 (poses::I &) const;
  void m_fn2 ()
  {
    I p;
    m_fn1 (p);
  }
};
class K : utils::J, public utils::D
{
};
struct F
{
  K *operator->();
};
class N : public K
{
  void m_fn1 (int &p1, int);
  void m_fn1 (I &) const {}
};
class L;
struct M
{
  L *operator->();
};
class L
{
public:
  F poseChange;
};
class G
{
  G ();
};
}

using namespace utils;
M h;
G::G () try
{
  N f;
  f.m_fn2 ();
  throw;
}

catch (int) {}

void fn1 () { h->poseChange->m_fn2 (); }

markus@x4 tmp % g++ -c -O2 test.ii
test.ii:68:40: internal compiler error: Segmentation fault
Comment 11 Martin Jambor 2014-03-19 10:44:42 UTC
Good job reducing the testcase to something this small!

Anyway, Jakub's analysis of what is going on is still correct and all
the high level decisions that we do are IMHO correct too.  The
invocation of symtab_remove_unreachable_symbols that removes the
callers is called with before_inlining_p set to false, even though
that is not technically right, we are still in the middle of inlining
because we are about to inline functions which are called only once.
But the comment in function ipa_inline says this is deliberate because
it helps to find the functions which are only called once.

However, this means that when symtab_remove_unreachable_symbols
correctly figures out that we can devirtualize to the offending thunk,
it assumes that cannot lead to any further inlining.  Because the
thunk is keyed in another compilation unit, it decides it only needs
to keep the symtab node but not the body.  In its terminology, the
node is in the "boundary".  The way the function cripples these
boundary nodes is actually the problem because it removes all callees
but not the thunk flag.  This leaves us with a thunk with no callee,
something that should not happen (and there is even a bit in the call
graph verifier that checks it).  Later on, we do perform this
devirtualization during inlining of functions only called once and
connect the crippled thunk to the call graph.  The first time we want
to follow through it, we segfault.

I believe that we do not want to allow thunks with no callees.  This
would mean changing every user of cgraph_function_node so that it can
cope with NULL return value and that is ugly and inconvenient.  This
leaves us with two options.  Either we make
symtab_remove_unreachable_symbols keep callees of thunks when it keeps
the thunk or we simply clear the thunk_p flag.  Given that thunks and
aliases are quite similar and we do clear the alias flag, and that
this should only ever affect nodes that we are not going to output, I
tend to believe the second approach is OK and of course it is much
simpler.  But before I propose the following fix on the mailing list,
I'll try to build some big C++ application with it:

diff --git a/gcc/ipa.c b/gcc/ipa.c
index 572dba1..164de0d 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -488,6 +488,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
              node->definition = false;
              node->cpp_implicit_alias = false;
              node->alias = false;
+             node->thunk.thunk_p = false;
              node->weakref = false;
              if (!node->in_other_partition)
                node->local.local = false;
Comment 12 Jakub Jelinek 2014-03-20 09:22:25 UTC
Slightly more reduced testcase:

--- gcc/testsuite/g++.dg/ipa/pr60419.C	2014-03-19 15:57:57.735114622 +0100
+++ gcc/testsuite/g++.dg/ipa/pr60419.C	2014-03-20 10:20:56.245365852 +0100
@@ -0,0 +1,68 @@
+// PR middle-end/60419
+// { dg-do compile }
+// { dg-options "-O2" }
+
+struct J
+{
+  J ();
+  virtual void foo (int &, int);
+};
+
+struct D
+{
+  virtual void foo (J &) const;
+  void bar ()
+  {
+    J p;
+    foo (p);
+  }
+};
+
+struct K : J, public D
+{
+};
+
+struct F
+{
+  K *operator->();
+};
+
+struct N : public K
+{
+  void foo (int &, int);
+  void foo (J &) const {}
+};
+
+struct L
+{
+  F l;
+};
+
+struct M
+{
+  L *operator->();
+};
+
+struct G
+{
+  G ();
+};
+
+M h;
+
+G::G ()
+try
+{
+  N f;
+  f.bar ();
+  throw;
+}
+catch (int)
+{
+}
+
+void
+baz ()
+{
+  h->l->bar ();
+}
Comment 13 Markus Trippelsdorf 2014-03-20 09:37:20 UTC
The problem with both pasted testcases is that they don't crash 4.7.4.
The attached one does.
Comment 14 Markus Trippelsdorf 2014-03-20 09:38:00 UTC
(In reply to Markus Trippelsdorf from comment #13)
> The problem with both pasted testcases is that they don't crash 4.7.4.
                                                                  4.8.3
of course
Comment 15 Markus Trippelsdorf 2014-03-20 09:55:30 UTC
So, what about (crashes trunk and 4.8.3) :

class J
{
public:
  J ();
  virtual void m_fn1 (int &p1, int);
};
template <class TDATA> class D
{
public:
  virtual void m_fn1 (TDATA &) const;
  void m_fn2 ()
  {
    TDATA p;
    m_fn1 (p);
  }
};

class I : J
{
};
class K : J, public D<I>
{
};
struct F
{
  K *operator->();
};
class N : public K
{
  void m_fn1 (int &p1, int);
  I mean;
  void m_fn1 (I &) const {}
};
class L;
struct M : F
{
  L *operator->();
};
class L : J
{
public:
  F poseChange;
};
class G
{
  G ();
};
M h;
G::G () try
{
  N f;
  f.m_fn2 ();
  throw;
}

catch (int) {}

void fn1 () { h->poseChange->m_fn2 (); }
Comment 16 Jakub Jelinek 2014-03-20 10:15:52 UTC
I have:
--- gcc/testsuite/g++.dg/ipa/pr60419.C	2014-03-19 15:57:57.735114622 +0100
+++ gcc/testsuite/g++.dg/ipa/pr60419.C	2014-03-20 11:13:58.933256068 +0100
@@ -0,0 +1,80 @@
+// PR middle-end/60419
+// { dg-do compile }
+// { dg-options "-O2" }
+
+struct C
+{
+};
+
+struct I : C
+{
+  I ();
+};
+
+struct J
+{
+  void foo ();
+  J ();
+  virtual void foo (int &, int);
+};
+
+template <class>
+struct D
+{
+  virtual void foo (I &) const;
+  void bar ()
+  {
+    I p;
+    foo (p);
+  }
+};
+
+struct K : J, public D<int>
+{
+};
+
+struct F
+{
+  K *operator->();
+};
+
+struct N : public K
+{
+  void foo (int &, int);
+  I n;
+  void foo (I &) const {}
+};
+
+struct L : J
+{
+  F l;
+};
+
+struct M : F
+{
+  L *operator->();
+};
+
+struct G
+{
+  G ();
+};
+
+M h;
+
+G::G ()
+try
+{
+  N f;
+  f.bar ();
+  throw;
+}
+catch (int)
+{
+}
+
+void
+baz ()
+{
+  h->l->bar ();
+}
Comment 17 Martin Jambor 2014-03-20 16:28:28 UTC
Trunk patch posted to the mailing list:

http://gcc.gnu.org/ml/gcc-patches/2014-03/msg01078.html

4.8 will need some slightly modified variant, I'm still looking for the best place to reset the flag there.
Comment 18 Martin Jambor 2014-03-21 12:48:34 UTC
Author: jamborm
Date: Fri Mar 21 12:48:02 2014
New Revision: 208747

URL: http://gcc.gnu.org/viewcvs?rev=208747&root=gcc&view=rev
Log:
2014-03-21  Martin Jambor  <mjambor@suse.cz>

	PR ipa/60419
	* ipa.c (symtab_remove_unreachable_nodes): Clear thunk flag of nodes
	in the border.

testsuite/
	* g++.dg/ipa/pr60419.C: New test.


Added:
    trunk/gcc/testsuite/g++.dg/ipa/pr60419.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/ipa.c
    trunk/gcc/testsuite/ChangeLog
Comment 19 Jakub Jelinek 2014-03-21 14:27:40 UTC
Fixed on the trunk so far.
Comment 20 Martin Jambor 2014-03-26 13:48:18 UTC
Author: jamborm
Date: Wed Mar 26 13:47:46 2014
New Revision: 208844

URL: http://gcc.gnu.org/viewcvs?rev=208844&root=gcc&view=rev
Log:
2014-03-26  Martin Jambor  <mjambor@suse.cz>

      PR ipa/60419
      * ipa.c (symtab_remove_unreachable_nodes): Clear thunk and
      alias flags of nodes in the border.

testsuite/
      * g++.dg/ipa/pr60419.C: New test.


Added:
    branches/gcc-4_8-branch/gcc/testsuite/g++.dg/ipa/pr60419.C
Modified:
    branches/gcc-4_8-branch/gcc/ChangeLog
    branches/gcc-4_8-branch/gcc/ipa.c
    branches/gcc-4_8-branch/gcc/testsuite/ChangeLog
Comment 21 Martin Jambor 2014-03-26 13:50:52 UTC
Fixed on 4.8 as well.