[RFA][PATCH][P2][PR middle-end/80422] Fix crossjumping ICE

Jeff Law law@redhat.com
Mon Apr 17 17:29:00 GMT 2017



A forwarder block becomes unreachable during cfg_cleanup. Later we're 
cross jumping an indirect (via more forwarders) successor of the now 
unreachable forwarder and walk up the CFG looking for hunks of 
equivalent insns and walk back into the unreachable forwarder block.  We 
then want to look at the predecessors and boom we ICE.

--

If we look at try_crossjump_to_edge we see the check to verify that SRC1 
and SRC2 both have predecessors:


   /* Likewise with dead code (possibly newly created by the other 
optimizations
      of cfg_cleanup).  */
   if (EDGE_COUNT (src1->preds) == 0 || EDGE_COUNT (src2->preds) == 0)
     return false;

Clearly someone was aware that we could have unreachable blocks when 
this code runs.

Then later we find call flow_find_cross_jump which walks up the insn 
chain, potentially leaving SRC1/SRC2 (by design).  When that happens we 
reset SRC1/SRC2:

   /* ... and part the second.  */
   nmatch = flow_find_cross_jump (src1, src2, &newpos1, &newpos2, &dir);

   osrc1 = src1;
   osrc2 = src2;
   if (newpos1 != NULL_RTX)
     src1 = BLOCK_FOR_INSN (newpos1);
   if (newpos2 != NULL_RTX)
     src2 = BLOCK_FOR_INSN (newpos2);

[ ... ]


A short time later we do this:

   /* Avoid splitting if possible.  We must always split when SRC2 has
      EH predecessor edges, or we may end up with basic blocks with both
      normal and EH predecessor edges.  */
   if (newpos2 == BB_HEAD (src2)
       && !(EDGE_PRED (src2, 0)->flags & EDGE_EH))
     redirect_to = src2;


If SRC2 is unreachable, then EDGE_PRED will read outside the vec's 
boundary triggering the fault.

The fix is pretty simple.  Check that SRC1/SRC2 have preds after the 
call to flow_find_cross_jump.

Bootstrapped and regression tested on x86_64-linux-gnu.

OK for the trunk?

Jeff

-------------- next part --------------
	PR middle-end/80422
	* cfgcleanup.c (try_crossjump_to_edge): Verify SRC1 and SRC2 have
	predecessors after walking up the insn chain.


	PR middle-end/80422
	* gcc.c-torture/compile/pr80422.c: New test.

diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index d55b0ce..f68a964 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -2017,6 +2017,11 @@ try_crossjump_to_edge (int mode, edge e1, edge e2,
   if (newpos2 != NULL_RTX)
     src2 = BLOCK_FOR_INSN (newpos2);
 
+  /* Check that SRC1 and SRC2 have preds again.  They may have changed
+     above due to the call to flow_find_cross_jump.  */
+  if (EDGE_COUNT (src1->preds) == 0 || EDGE_COUNT (src2->preds) == 0)
+    return false;
+
   if (dir == dir_backward)
     {
 #define SWAP(T, X, Y) do { T tmp = (X); (X) = (Y); (Y) = tmp; } while (0)
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr80422.c b/gcc/testsuite/gcc.c-torture/compile/pr80422.c
new file mode 100644
index 0000000..2cece67
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr80422.c
@@ -0,0 +1,26 @@
+
+int a, c, f;
+short b, d, e;
+
+int fn1 (int h)
+{ 
+  return a > 2 || h > a ? h : h << a;
+}
+
+void fn2 ()
+{ 
+  int j, k;
+  while (1)
+    { 
+      k = c && b;
+      f &= e > (fn1 (k) && j);
+      if (!d)
+        break;
+    }
+}
+
+int main ()
+{ 
+  fn2 ();
+  return 0;
+}


More information about the Gcc-patches mailing list