Avoid overflow in ipa-modref-tree.cc

Message ID YlNd0M1e7GBGkTtX@kam.mff.cuni.cz
State New
Headers
Series Avoid overflow in ipa-modref-tree.cc |

Commit Message

Jan Hubicka April 10, 2022, 10:44 p.m. UTC
  Hi,
the testcase triggers ICE since computation overflows on two accesses
that are very far away d->b[-144115188075855873] and d->b[144678138029277184].
This patch makes the relevant part of modref to use poly_offset_int.

It is kind of weird to store bit offsets into poly_int64 but it is what
alias oracle does.  There are some other places where computations are
done that may overflow, I will fix them incrementally (it is not
completely mechanical due to signed/unsigned info).

Bootstrapped/regtested x86_64-linux.  I plan to commit it tomorrow if
there are no complains.

gcc/ChangeLog:

2022-04-11  Jan Hubicka  <hubicka@ucw.cz>

	* ipa-modref-tree.cc (modref_access_node::closer_pair_p): Use
	poly_offset_int to avoid overflow.
	(modref_access_node::update2): Likewise.

gcc/testsuite/ChangeLog:

2022-04-11  Jan Hubicka  <hubicka@ucw.cz>

	* gcc.c-torture/compile/103818.c: New test.
  

Comments

Jakub Jelinek April 12, 2022, 11:01 a.m. UTC | #1
On Mon, Apr 11, 2022 at 12:44:32AM +0200, Jan Hubicka via Gcc-patches wrote:
> Hi,
> the testcase triggers ICE since computation overflows on two accesses
> that are very far away d->b[-144115188075855873] and d->b[144678138029277184].
> This patch makes the relevant part of modref to use poly_offset_int.
> 
> It is kind of weird to store bit offsets into poly_int64 but it is what
> alias oracle does.  There are some other places where computations are
> done that may overflow, I will fix them incrementally (it is not
> completely mechanical due to signed/unsigned info).
> 
> Bootstrapped/regtested x86_64-linux.  I plan to commit it tomorrow if
> there are no complains.
> 
> gcc/ChangeLog:
> 
> 2022-04-11  Jan Hubicka  <hubicka@ucw.cz>
> 

Please add
	PR ipa/103818
so that it will link to bugzilla.

> 	* ipa-modref-tree.cc (modref_access_node::closer_pair_p): Use
> 	poly_offset_int to avoid overflow.
> 	(modref_access_node::update2): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 2022-04-11  Jan Hubicka  <hubicka@ucw.cz>
> 
> 	* gcc.c-torture/compile/103818.c: New test.
> 
> diff --git a/gcc/ipa-modref-tree.cc b/gcc/ipa-modref-tree.cc
> index f19af8c2b55..44cb645954f 100644
> --- a/gcc/ipa-modref-tree.cc
> +++ b/gcc/ipa-modref-tree.cc
> @@ -267,34 +267,42 @@ modref_access_node::closer_pair_p (const modref_access_node &a1,
>  
>  
>    /* Now compute distance of the intervals.  */
> -  poly_int64 dist1, dist2;
> +  poly_offset_int dist1, dist2;
>    if (known_le (offseta1, offsetb1))
>      {
>        if (!known_size_p (a1.max_size))
>  	dist1 = 0;
>        else
> -	dist1 = offsetb1 - offseta1 - a1.max_size;
> +	dist1 = (poly_offset_int)offsetb1
> +		- (poly_offset_int)offseta1
> +		- (poly_offset_int)a1.max_size;

I think we usually put a space between the (type) and
following expression after it.

> --- /dev/null
> +++ b/gcc/testsuite/gcc.c-torture/compile/103818.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target lp64 } } */
> +struct a {
> +  int b[0];
> +} c(struct a *d) {
> +  d->b[0] = d->b[-144115188075855873] + d->b[11] * d->b[2] +
> +            d->b[0] % d->b[1025] + d->b[5];
> +  d->b[0] =
> +      d->b[144678138029277184] + d->b[0] & d->b[-3] * d->b[053] + d->b[7] ^
> +      d->b[-9] + d->b[14] + d->b[9] % d->b[49] + d->b[024] + d->b[82] &
> +          d->b[4096];
> +}
> +void main() {}

Can you please slightly fix up the testcase?
I mean e.g. the struct a definition in return type of c when it doesn't
return anything or main returning void (when it isn't needed at all)
are unnecessary, and the lp64 requirement can be avoided by using LL
suffix on the 2 large indexes.  Also, having the b[0] array and
b[0] accesses isn't necessary for the ICE.  So say:
struct A { int b[1]; };

void
foo (struct A *d)
{
  d->b[0] = d->b[-144115188075855873LL] + d->b[11] * d->b[2]
	    + d->b[0] % d->b[1025] + d->b[5];
  d->b[0] = d->b[144678138029277184LL] + d->b[0] & d->b[-3] * d->b[053]
	    + d->b[7] ^ d->b[-9] + d->b[14] + d->b[9] % d->b[49]
	    + d->b[024] + d->b[82] & d->b[4096];
}
?  Sure, the testcase is still heavily invalid, but slightly less so.

Otherwise LGTM, thanks for fixing it.

	Jakub
  

Patch

diff --git a/gcc/ipa-modref-tree.cc b/gcc/ipa-modref-tree.cc
index f19af8c2b55..44cb645954f 100644
--- a/gcc/ipa-modref-tree.cc
+++ b/gcc/ipa-modref-tree.cc
@@ -267,34 +267,42 @@  modref_access_node::closer_pair_p (const modref_access_node &a1,
 
 
   /* Now compute distance of the intervals.  */
-  poly_int64 dist1, dist2;
+  poly_offset_int dist1, dist2;
   if (known_le (offseta1, offsetb1))
     {
       if (!known_size_p (a1.max_size))
 	dist1 = 0;
       else
-	dist1 = offsetb1 - offseta1 - a1.max_size;
+	dist1 = (poly_offset_int)offsetb1
+		- (poly_offset_int)offseta1
+		- (poly_offset_int)a1.max_size;
     }
   else
     {
       if (!known_size_p (b1.max_size))
 	dist1 = 0;
       else
-	dist1 = offseta1 - offsetb1 - b1.max_size;
+	dist1 = (poly_offset_int)offseta1
+		 - (poly_offset_int)offsetb1
+		 - (poly_offset_int)b1.max_size;
     }
   if (known_le (offseta2, offsetb2))
     {
       if (!known_size_p (a2.max_size))
 	dist2 = 0;
       else
-	dist2 = offsetb2 - offseta2 - a2.max_size;
+	dist2 = (poly_offset_int)offsetb2
+		- (poly_offset_int)offseta2
+		- (poly_offset_int)a2.max_size;
     }
   else
     {
       if (!known_size_p (b2.max_size))
 	dist2 = 0;
       else
-	dist2 = offseta2 - offsetb2 - b2.max_size;
+	dist2 = offseta2
+		- (poly_offset_int)offsetb2
+		- (poly_offset_int)b2.max_size;
     }
   /* It may happen that intervals overlap in case size
      is different.  Prefer the overlap to non-overlap.  */
@@ -380,9 +388,16 @@  modref_access_node::update2 (poly_int64 parm_offset1,
     new_max_size = max_size2;
   else
     {
-      new_max_size = max_size2 + offset2 - offset1;
-      if (known_le (new_max_size, max_size1))
-	new_max_size = max_size1;
+      poly_offset_int s = (poly_offset_int)max_size2
+			  + (poly_offset_int)offset2
+			  - (poly_offset_int)offset1;
+      if (s.to_shwi (&new_max_size))
+	{
+	  if (known_le (new_max_size, max_size1))
+	    new_max_size = max_size1;
+	}
+      else
+	new_max_size = -1;
     }
 
   update (parm_offset1, offset1,
diff --git a/gcc/testsuite/gcc.c-torture/compile/103818.c b/gcc/testsuite/gcc.c-torture/compile/103818.c
new file mode 100644
index 00000000000..8a0148e243a
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/103818.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile { target lp64 } } */
+struct a {
+  int b[0];
+} c(struct a *d) {
+  d->b[0] = d->b[-144115188075855873] + d->b[11] * d->b[2] +
+            d->b[0] % d->b[1025] + d->b[5];
+  d->b[0] =
+      d->b[144678138029277184] + d->b[0] & d->b[-3] * d->b[053] + d->b[7] ^
+      d->b[-9] + d->b[14] + d->b[9] % d->b[49] + d->b[024] + d->b[82] &
+          d->b[4096];
+}
+void main() {}