Fix ICE in find_taken_edge_computed_goto (PR 84136)
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 9 Feb 2018 01:07:11 +0000 (01:07 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Fri, 9 Feb 2018 01:07:11 +0000 (01:07 +0000)
PR 84136 reports an ICE within sccvn_dom_walker when handling a
C/C++ source file that overuses the labels-as-values extension.
The code in question stores a jump label into a global, and then
jumps to it from another function, which ICEs after inlining:

void* a;

void foo() {
  if ((a = &&l))
      return;

  l:;
}

int main() {
  foo();
  goto *a;

  return 0;
}

This appears to be far beyond what we claim to support in this
extension - but we shouldn't ICE.

What's happening is that, after inlining, we have usage of a *copy*
of the label, which optimizes away the if-return logic, turning it
into an infinite loop.

On entry to the sccvn_dom_walker we have this gimple:

main ()
{
  void * a.0_1;

  <bb 2> [count: 0]:
  a = &l;

  <bb 3> [count: 0]:
l:
  a.0_1 = a;
  goto a.0_1;
}

and:
  edge taken = find_taken_edge (bb, vn_valueize (val));
reasonably valueizes the:
  goto a.0_1;
after the:
  a = &l;
  a.0_1 = a;
as if it were:
  goto *&l;

find_taken_edge_computed_goto then has:

2380   dest = label_to_block (val);
2381   if (dest)
2382     {
2383       e = find_edge (bb, dest);
2384       gcc_assert (e != NULL);
2385     }

which locates dest as a self-jump from block 3 back to itself.

However, the find_edge call returns NULL - it has a predecessor edge
from block 2, but no successor edges.

Hence the assertion fails and we ICE.

A successor edge from the computed goto could have been created by
make_edges if the label stmt had been in the function, but make_edges
only looks in the current function when handling computed gotos, and
the label only appeared after inlining.

The following patch removes the assertion, fixing the ICE.

gcc/testsuite/ChangeLog:
PR tree-optimization/84136
* gcc.c-torture/compile/pr84136.c: New test.

gcc/ChangeLog:
PR tree-optimization/84136
* tree-cfg.c (find_taken_edge_computed_goto): Remove assertion
that the result of find_edge is non-NULL.

From-SVN: r257509

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/pr84136.c [new file with mode: 0644]
gcc/tree-cfg.c

index dd78a342cdf218b8cb18734389c63d7f586cf1e3..8212952e8d8e9538bfac29d36deb55aeb40184fc 100644 (file)
@@ -1,3 +1,9 @@
+2018-02-08  David Malcolm  <dmalcolm@redhat.com>
+
+       PR tree-optimization/84136
+       * tree-cfg.c (find_taken_edge_computed_goto): Remove assertion
+       that the result of find_edge is non-NULL.
+
 2018-02-08  Sergey Shalnov  <sergey.shalnov@intel.com>
 
        PR target/83008
index d9ed50cd3229316ccf6a53d3980640231c9245fe..dfa8cb87d930d0e9e16a6e0c01b3e6f55bc50569 100644 (file)
@@ -1,3 +1,8 @@
+2018-02-08  David Malcolm  <dmalcolm@redhat.com>
+
+       PR tree-optimization/84136
+       * gcc.c-torture/compile/pr84136.c: New test.
+
 2018-02-08  Sergey Shalnov  <sergey.shalnov@intel.com>
 
        PR target/83008
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr84136.c b/gcc/testsuite/gcc.c-torture/compile/pr84136.c
new file mode 100644 (file)
index 0000000..0a70e4e
--- /dev/null
@@ -0,0 +1,15 @@
+void* a;
+
+void foo() {
+    if ((a = &&l))
+        return;
+
+    l:;
+}
+
+int main() {
+    foo();
+    goto *a;
+
+    return 0;
+}
index c5318b92c69d965af2c24ce88fa0df086e610ac0..b87e48dade6309c9668f21f106d1d53d30a0cb40 100644 (file)
@@ -2379,10 +2379,14 @@ find_taken_edge_computed_goto (basic_block bb, tree val)
 
   dest = label_to_block (val);
   if (dest)
-    {
-      e = find_edge (bb, dest);
-      gcc_assert (e != NULL);
-    }
+    e = find_edge (bb, dest);
+
+  /* It's possible for find_edge to return NULL here on invalid code
+     that abuses the labels-as-values extension (e.g. code that attempts to
+     jump *between* functions via stored labels-as-values; PR 84136).
+     If so, then we simply return that NULL for the edge.
+     We don't currently have a way of detecting such invalid code, so we
+     can't assert that it was the case when a NULL edge occurs here.  */
 
   return e;
 }