Bug 27882 - [4.1 regression] segfault in ipa-inline.c, if (e->callee->local.disregard_inline_limits
Summary: [4.1 regression] segfault in ipa-inline.c, if (e->callee->local.disregard_inl...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 4.2.0
: P2 normal
Target Milestone: 4.2.0
Assignee: Jan Hubicka
URL:
Keywords: GC, ice-on-valid-code
Depends on: 23408
Blocks:
  Show dependency treegraph
 
Reported: 2006-06-03 10:14 UTC by Martin Michlmayr
Modified: 2008-07-04 15:34 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.2.0
Known to fail: 4.1.3
Last reconfirmed: 2006-07-19 12:44:48


Attachments
test case (24.44 KB, text/plain)
2006-06-03 10:18 UTC, Martin Michlmayr
Details
less reduced test case (57.35 KB, text/plain)
2006-06-03 21:20 UTC, Martin Michlmayr
Details
shorest testcase I can reduce to (1.21 KB, text/plain)
2006-06-07 05:19 UTC, Andrew Pinski
Details
C test case (81.14 KB, application/octet-stream)
2006-06-12 18:03 UTC, Martin Michlmayr
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Michlmayr 2006-06-03 10:14:26 UTC
I get a segfault with 20060530 when building xstow that I didn't get with
20060508.  The segfault doesn't show up when I run g++ on the preprocessed
file but pinskia pointed out that I should use --param ggc-min-expand=0
--param ggc-min-heapsize=0, and indeed, when I add --param ggc-min-expand=0
I see it - but also with 20060508.

It turns out that this segfault was introduced sometime between 20060325
and 20060419.  (And, in fact, compiling xstow with 20060419 also segfaults,
just not 20060508.)

(sid)492:tbm@reyes: ~] /usr/lib/gcc-snapshot/bin/g++ -c --param ggc-min-expand=0 -O2 segfault.c
segfault.c:3617: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.
zsh: exit 1     /usr/lib/gcc-snapshot/bin/g++ -c --param ggc-min-expand=0 -O2 segfault.c
(sid)493:tbm@reyes: ~] /usr/lib/gcc-snapshot/bin/g++ -c --param ggc-min-expand=0 segfault.c
(sid)494:tbm@reyes: ~]

Program received signal SIGSEGV, Segmentation fault.
cgraph_decide_inlining_incrementally (node=0x8d619d00, early=1 '\001')
    at /home/tbm/scratch/gcc/gcc/ipa-inline.c:1055
1055        if (e->callee->local.disregard_inline_limits
(gdb) where
#0  cgraph_decide_inlining_incrementally (node=0x8d619d00, early=1 '\001')
    at /home/tbm/scratch/gcc/gcc/ipa-inline.c:1055
#1  0x085835bd in cgraph_early_inlining () at /home/tbm/scratch/gcc/gcc/ipa-inline.c:1163
#2  0x0852c1e6 in execute_one_pass (pass=0x874b660) at /home/tbm/scratch/gcc/gcc/passes.c:864
#3  0x0852c417 in execute_ipa_pass_list (pass=0x874b660) at /home/tbm/scratch/gcc/gcc/passes.c:925
#4  0x0857f1f5 in cgraph_optimize () at /home/tbm/scratch/gcc/gcc/cgraphunit.c:1378
#5  0x080d66ca in cp_finish_file () at /home/tbm/scratch/gcc/gcc/cp/decl2.c:3112
#6  0x0819efff in c_common_parse_file (set_yydebug=0) at /home/tbm/scratch/gcc/gcc/c-opts.c:1165
#7  0x084f6f7d in toplev_main (argc=1, argv=0xaff02de4) at /home/tbm/scratch/gcc/gcc/toplev.c:999
#8  0xa7dc1eb0 in __libc_start_main () from /lib/tls/libc.so.6
#9  0x08049c11 in _start () at ../sysdeps/i386/elf/start.S:119
(gdb)
Comment 1 Martin Michlmayr 2006-06-03 10:18:31 UTC
Created attachment 11587 [details]
test case

test case... still fairly large but I've been running delta for 24 hours now
Comment 2 Martin Michlmayr 2006-06-03 10:19:25 UTC
Janis, do you think you can do a regression hunt on this bug?
Comment 3 Richard Biener 2006-06-03 20:36:56 UTC
Works for me with r114332 on i686.
Comment 4 Martin Michlmayr 2006-06-03 20:47:48 UTC
I was using revision 114238.  Do you know if there has been a change that might have fixed this?
Comment 5 rguenther@suse.de 2006-06-03 20:52:44 UTC
Subject: Re:  [4.2 regression] segfault in
 ipa-inline.c, if (e->callee->local.disregard_inline_limits

On Sat, 3 Jun 2006, tbm at cyrius dot com wrote:

> I was using revision 114238.  Do you know if there has been a change that might
> have fixed this?

I don't see anything obvious.
Comment 6 Martin Michlmayr 2006-06-03 21:20:07 UTC
Created attachment 11591 [details]
less reduced test case

This (less reduced) test case still shows the segfault with current SVN.  It takes fairly long though.
Comment 7 Janis Johnson 2006-06-05 19:45:31 UTC
A regression hunt on powerpc-linux using the less-reduced test case with the options "-O2 --param ggc-min-expand=0 --param ggc-min-heapsize=0" identified this patch:

    http://gcc.gnu.org/viewcvs?view=rev&rev=112753

    r112753 | hubicka | 2006-04-07 15:24:39 +0000 (Fri, 07 Apr 2006)
Comment 8 Andrew Pinski 2006-06-06 05:38:38 UTC
I am going to reduce this further.
Comment 9 Andrew Pinski 2006-06-07 05:19:15 UTC
Created attachment 11620 [details]
shorest testcase I can reduce to

This is the shorest testcase I could reduce this to, I did it on powerpc-darwin but I found removing some templates causes this to go "right" which seems wrong.
Comment 10 Andrew Pinski 2006-06-07 05:30:55 UTC
The last time I ran into this was back in 2005, and I had committed the following patch:
2005-08-29  Andrew Pinski  <pinskia@physics.uc.edu>

        PR middle-end/23408
        * ipa-inline.c (cgraph_decide_inlining_incrementally): Remove the
        call to ggc_collect.

So I had almost thought the gc problem would be an issue again :(.
Comment 11 Andrew Pinski 2006-06-07 05:50:48 UTC
The dtor for "Ref<std::vector<Ref<Node>, std::allocator<Ref<Node> > > >" is the node which has been freed.
Comment 12 Andrew Pinski 2006-06-07 06:00:48 UTC
Wait in tree-inline.c, we do:
  /* Update callgraph if needed.  */
  cgraph_remove_node (cg_edge->callee);

Isn't that wrong as we could inline the callee a couple of times?
Don't we want to do:
  /* Update callgraph if needed.  */
  cgraph_remove_edge (cg_edge);

???
Comment 13 Andrew Pinski 2006-06-07 06:37:32 UTC
Nothing I have tried so far has worked and I don't understand how we could remove a node from here.

Oh, I see remove node is correct, we duplicate the nodes which I did not know about until now.
Comment 14 Jan Hubicka 2006-06-07 12:18:31 UTC
Subject: Re:  [4.2 regression] segfault in ipa-inline.c, if (e->callee->local.disregard_inline_limits

> 
> 
> ------- Comment #12 from pinskia at gcc dot gnu dot org  2006-06-07 06:00 -------
> Wait in tree-inline.c, we do:
>   /* Update callgraph if needed.  */
>   cgraph_remove_node (cg_edge->callee);
> 
> Isn't that wrong as we could inline the callee a couple of times?

It should be OK - if we inline multiple times, we create multiple nodes.
I will look into this.

Honza
Comment 15 Richard Biener 2006-06-07 14:54:06 UTC
Note the problem is possibly at least latent on the 4.1 branch.
Comment 16 Martin Michlmayr 2006-06-07 16:12:21 UTC
I just got this segfault with when compiling another application.  Should I attach the preprocessed source to this PR or do you have enough information already to fix it?
Comment 17 Martin Michlmayr 2006-06-08 13:54:13 UTC
This segfault also shows up when compiling the Linux kernel (compiling file net/tipc/net.c).
Comment 18 Steven Bosscher 2006-06-11 08:36:28 UTC
A pre-processed C test case would be nice.
Comment 19 Martin Michlmayr 2006-06-12 18:03:59 UTC
Created attachment 11654 [details]
C test case

Here's a C test case (from the Linux kernel).

5289:tbm@reyes: ~] /usr/local/bin/gcc -c -O2 --param ggc-min-expand=0 --param ggc-min-heapsize=0 net.i
net/tipc/net.c:311: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.
zsh: exit 1     /usr/local/bin/gcc -c -O2 --param ggc-min-expand=0 --param ggc-min-heapsize=0
Comment 20 Martin Michlmayr 2006-06-12 20:18:36 UTC
Finally, a *small* test case.

5336:tbm@reyes: ~/tmp/delta/bin] /usr/local/bin/gcc -c -O1 --param ggc-min-expand=0 --param ggc-min-heapsize=0 mini.c
mini.c:27: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.
5337:tbm@reyes: ~/tmp/delta/bin] /usr/local/bin/gcc -c --param ggc-min-expand=0 --param ggc-min-heapsize=0 mini.c
5338:tbm@reyes: ~/tmp/delta/bin] cat mini.c
struct sk_buff
{
}
raw_hdlc_proto;
     struct tipc_msg *buf_msg (struct sk_buff *skb)
{
}
     void buf_discard (struct sk_buff *skb)
{
}
void tipc_net_route_msg (struct sk_buff *buf);
static inline __attribute__ ((always_inline))
     tipc_port_recv_msg (struct sk_buff *buf)
{
    {
      tipc_net_route_msg (buf);
    }
}
void
tipc_net_route_msg (struct sk_buff *buf)
{
    {
        {
            tipc_port_recv_msg (buf);
        }
    }
}
5339:tbm@reyes: ~/tmp/delta/bin]
Comment 21 Volker Reichelt 2006-07-19 12:44:48 UTC
I cannot reproduce the ICE with the original testcase.
I can reproduce it with the testcase from comment #19 and #20, though.
Here's an even shorter version:

=======================
void foo();

static inline bar()
{
    foo();
}

void foo()
{
    bar();
}
=======================

In addition I can only reproduce the problem on the 4.1 branch, starting
with GCC 4.1.1, but not on mainline (probably latent, though).
Comment 22 Richard Biener 2006-07-19 13:19:38 UTC
I see what the problem is.  cgraph_postorder doesn't help us if we're having a cycle like here, so

  nnodes = cgraph_postorder (order);
  for (i = nnodes - 1; i >= 0; i--)
    {
      node = order[i];
      if (node->analyzed && node->local.inlinable
          && (node->needed || node->reachable)
          && node->callers)
        {
          if (cgraph_decide_inlining_incrementally (node, true))
            ggc_collect ();
        }
    }

after inlining into foo, which we do first, bar is no longer referenced
and is collected.  We still reference it from order[0] though.
Comment 23 Richard Biener 2006-07-19 13:31:55 UTC
I have a patch:

Index: ipa-inline.c
===================================================================
--- ipa-inline.c        (revision 115554)
+++ ipa-inline.c        (working copy)
@@ -1133,6 +1133,7 @@ cgraph_early_inlining (void)
   struct cgraph_node **order =
     xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
   int i;
+  htab_t cycles;
 
   if (sorrycount || errorcount)
     return;
@@ -1142,6 +1143,8 @@ cgraph_early_inlining (void)
 #endif
 
   nnodes = cgraph_postorder (order);
+  cycles = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL);
+  cgraph_find_cycles (cgraph_nodes, cycles);
   for (i = nnodes - 1; i >= 0; i--)
     {
       node = order[i];
@@ -1149,10 +1152,13 @@ cgraph_early_inlining (void)
          && (node->needed || node->reachable)
          && node->callers)
        {
-         if (cgraph_decide_inlining_incrementally (node, true))
+         if (cgraph_decide_inlining_incrementally (node, true)
+             /* Avoid collecting if inlining in a cycle.  */
+             && !htab_find (cycles, node))
            ggc_collect ();
        }
     }
+  htab_delete (cycles);
   cgraph_remove_unreachable_nodes (true, dump_file);
 #ifdef ENABLE_CHECKING
   for (node = cgraph_nodes; node; node = node->next)
Comment 24 Richard Biener 2006-07-19 13:59:47 UTC
Hmm, it needs to find the root of the callgraph first.  Or all root nodes, and find cycles starting from there.
Comment 25 Richard Biener 2006-07-19 14:06:44 UTC
Simpler one goes along

@@ -1148,9 +1149,13 @@ cgraph_early_inlining (void)
       if (node->analyzed && node->local.inlinable
          && (node->needed || node->reachable)
          && node->callers)
+       inlined |= cgraph_decide_inlining_incrementally (node, true);
+      /* Collect at cgraph roots, which avoid collecting inside cycles.  */
+      if (inlined
+         && !node->callers)
        {
-         if (cgraph_decide_inlining_incrementally (node, true))
-           ggc_collect ();
+         ggc_collect ();
+         inlined = false;
        }
     }
   cgraph_remove_unreachable_nodes (true, dump_file);

but also has a greater impact on when we collect and when not possibly.
Comment 26 Jan Hubicka 2006-07-19 17:29:00 UTC
Well, I don't like much the limiting of inlining in recursive functions (where it is rather interesting)
and I can't convince myself that the second patch is safe (ie the cycle don't have to be in consetuctive entries in the postorder I would say).
I will test patch that simply make the array GGC root....

Thanks for looking into this,
Honza
Comment 27 Richard Biener 2006-07-20 08:29:08 UTC
I guess the patch format made it hard to see what the result is.  It looks like

  nnodes = cgraph_postorder (order);
  for (i = nnodes - 1; i >= 0; i--)
    {
      node = order[i];
      if (node->analyzed && node->local.inlinable
          && (node->needed || node->reachable)
          && node->callers)
        inlined |= cgraph_decide_inlining_incrementally (node, true);
      /* Collect at cgraph roots, which avoids collecting inside cycles.  */
      if (inlined
          && !node->callers)
        {
          ggc_collect ();
          inlined = false;
        }
    }

i.e. inlining is unchanged, only collection is done at a different point.
(for pure luck this saves some kB of peak memory usage and compile-time on tramp3d).  For the postorder I assumed that inlining for cgraph roots
(nodes with no callers) is decided not during deciding for inlining inside
a cycle.  One could extend this to also collect for cgraph tails, I think,
making it !node->callers || !node->callees.

Anyway, the patch gcac tested for C and C++ on x86_64-unknown-linux-gnu.

And I suspect that if you make 'order' gc allocated you'll loose the
ability to effectively collect garbage here.
Comment 28 Jan Hubicka 2006-07-26 20:17:42 UTC
Subject: Bug 27882

Author: hubicka
Date: Wed Jul 26 20:17:32 2006
New Revision: 115763

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=115763
Log:
	PR tree-optimization/27882
	* cgraph.c (cgraph_remove_node): Clear needed, reachable, next, previous
	and decl fields.
	* cgraphunit.c (cgraph_reset_node): Expect cgraph_remove_node to kill
	next pointer
	(cgraph_analyze_compilation_unit): Likewise.
	* ipa.c (cgraph_remove_unreachable_nodes): Likewise.
	* ipa-inline.c (cgraph_decide_recursive_inlining): Likewise.
	(cgraph_early_inlinine): Make order garbage collected.
	* Makefile.in (gt-ipa-inline): New garbagecollected file.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/Makefile.in
    trunk/gcc/cgraph.c
    trunk/gcc/cgraphunit.c
    trunk/gcc/ipa-inline.c
    trunk/gcc/ipa.c

Comment 29 Joseph S. Myers 2008-07-04 15:34:20 UTC
Closing 4.1 branch.