From: David Malcolm Date: Fri, 9 Feb 2018 01:07:11 +0000 (+0000) Subject: Fix ICE in find_taken_edge_computed_goto (PR 84136) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6d3aa24cd6535dcfc9f0701579eca53aa191768c;p=gcc.git Fix ICE in find_taken_edge_computed_goto (PR 84136) 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; [count: 0]: a = &l; [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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dd78a342cdf..8212952e8d8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2018-02-08 David Malcolm + + 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 PR target/83008 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d9ed50cd322..dfa8cb87d93 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-02-08 David Malcolm + + PR tree-optimization/84136 + * gcc.c-torture/compile/pr84136.c: New test. + 2018-02-08 Sergey Shalnov 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 index 00000000000..0a70e4e3203 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr84136.c @@ -0,0 +1,15 @@ +void* a; + +void foo() { + if ((a = &&l)) + return; + + l:; +} + +int main() { + foo(); + goto *a; + + return 0; +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index c5318b92c69..b87e48dade6 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -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; }