Bug 82177

Summary: Alias analysis too aggressive with integer-to-pointer cast
Product: gcc Reporter: Nuno Lopes <nunoplopes>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: gabravier, kristerw, pageexec, regehr, rguenth, sjames
Priority: P3 Keywords: alias, wrong-code
Version: 7.2.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed:
Bug Depends on: 61502, 65752    
Bug Blocks:    

Description Nuno Lopes 2017-09-11 12:51:15 UTC
The following code gets miscompiled with gcc:

#include <stdio.h>
#include <stdint.h>

void f(int*, int*);

int main()
{
  int a=0, y[1], x = 0;
  uintptr_t pi = (uintptr_t) &x;
  uintptr_t yi = (uintptr_t) (y+1);
  uintptr_t n = pi != yi;

  if (n) {
    a = 100;
    pi = yi;
  }

  if (n) {
    a = 100;
    pi = (uintptr_t) y;
  }

  *(int *)pi = 15;

  printf("a=%d x=%d\n", a, x);

  f(&x,y);

  return 0;
}


$ gcc -O2 c.c b.c -o foo

$ ./foo
a=0 x=0

This result is wrong.  The two possible outcomes are: a=0 x=15, and a=100 x=0.

The bug seems to be in the alias analysis, which is not conservative enough in handling integer-to-pointer casts. The wrong transformation happens at this point (dump with -fdump-tree-all):

$ cat c.c.123t.pre
yi_8 = { y }
y = { ESCAPED NONLOCAL }
pi_4 = { y } same as yi_8
pi_9 = { y } same as yi_8
pi.0_10 = { y } same as yi_8

(...)

  pi_7 = (uintptr_t) &x;
  yi_8 = (uintptr_t) &MEM[(void *)&y + 4B];
  if (pi_7 != yi_8)
    goto <bb 4>;
  else
    goto <bb 3>;

  <bb 3>:
  # a_2 = PHI <0(2), 100(4)>
  # pi_4 = PHI <yi_8(2), pi_9(4)>
  pi.0_10 = (int *) pi_4;
  *pi.0_10 = 15;
  printf ("a=%d x=%d\n", a_2, 0);   // <-- constant folded across the *pi store
                                    // because it was incorrectly proven to not
                                    // alias with x

Test case by Gil Hur.
Comment 1 Andrew Pinski 2017-09-11 12:55:50 UTC
I don't see how this can ever be defined code.

By definition yi will never be equal to pi unless by accident.
Comment 2 Nuno Lopes 2017-09-11 12:58:40 UTC
(In reply to Andrew Pinski from comment #1)
> I don't see how this can ever be defined code.
> 
> By definition yi will never be equal to pi unless by accident.

Sure, that's ok, but then pi = &x, and so the store '*(int*)pi = 15' should write to x.
Right now it's printing x=0, which cannot be correct.
Comment 3 Nuno Lopes 2017-09-11 16:19:05 UTC
Sorry, I forgot to include the code for b.c:

void f(int*x, int*y) {}
Comment 4 Richard Biener 2017-09-12 10:27:40 UTC
This is a dup of another PR which I can't find right now.  GCC handles pointer-to-integer casts just fine.  What it doesn't is creating alias relationship
by relational tests (! n) but at the same time it sometimes propagates
conditional equivalences (that's not the issue in your case I think).

As said in that PR an incomplete fix would be to do sth like

Index: gcc/tree-ssa-structalias.c
===================================================================
--- gcc/tree-ssa-structalias.c  (revision 251997)
+++ gcc/tree-ssa-structalias.c  (working copy)
@@ -4954,6 +4954,19 @@ find_func_aliases (struct function *fn,
            make_escape_constraint (rhsop);
        }
     }
+  else if (gcond *cond = dyn_cast <gcond *> (t))
+    {
+      if ((gimple_cond_code (cond) == EQ_EXPR
+          || gimple_cond_code (cond) == NE_EXPR)
+         && TREE_CODE (gimple_cond_rhs (cond)) == SSA_NAME)
+       {
+         auto_vec<ce_s> rhs1c;
+         auto_vec<ce_s> rhs2c;
+         get_constraint_for_rhs (gimple_cond_lhs (cond), &rhs1c);
+         get_constraint_for_rhs (gimple_cond_rhs (cond), &rhs2c);
+         process_all_all_constraints (rhs1c, rhs2c);
+       }
+    }
   /* Handle escapes through return.  */
   else if (gimple_code (t) == GIMPLE_RETURN
           && gimple_return_retval (as_a <greturn *> (t)) != NULL_TREE)

the effect on the number of constraints and optimization is unknown.

Incomplete because the above doesn't handle other ways of relating things.
The compare might be in an external function and thus not visible to GCC
at all.  Which means we must assume that all pointers that escaped the
current function might actually point to the same thing if a function
call happens (and the result is in any way used in a conditional).

You can workaround GCCs "deficiency" by using -fno-tree-pta.
Comment 5 Krister Walfridsson 2017-09-20 11:53:07 UTC
Did you mean PR61502 - "== comparison on "one-past" pointer gives wrong result"?
Comment 6 rguenther@suse.de 2017-09-20 12:17:45 UTC
On Wed, 20 Sep 2017, kristerw at gcc dot gnu.org wrote:

> --- Comment #5 from Krister Walfridsson <kristerw at gcc dot gnu.org> ---
> Did you mean PR61502 - "== comparison on "one-past" pointer gives wrong
> result"?

Yes, but I believe there's another one where I posted a similar
incomplete patch and explained why we can't possibly fix this
without making points-to analysis useless.
Comment 7 Eric Gallager 2017-09-24 00:46:53 UTC
(In reply to rguenther@suse.de from comment #6)
> On Wed, 20 Sep 2017, kristerw at gcc dot gnu.org wrote:
> 
> > --- Comment #5 from Krister Walfridsson <kristerw at gcc dot gnu.org> ---
> > Did you mean PR61502 - "== comparison on "one-past" pointer gives wrong
> > result"?
> 
> Yes, but I believe there's another one where I posted a similar
> incomplete patch and explained why we can't possibly fix this
> without making points-to analysis useless.

bug 65752 perhaps?
Comment 8 Eric Gallager 2018-01-05 13:32:39 UTC
(In reply to Eric Gallager from comment #7)
> (In reply to rguenther@suse.de from comment #6)
> > On Wed, 20 Sep 2017, kristerw at gcc dot gnu.org wrote:
> > 
> > > --- Comment #5 from Krister Walfridsson <kristerw at gcc dot gnu.org> ---
> > > Did you mean PR61502 - "== comparison on "one-past" pointer gives wrong
> > > result"?
> > 
> > Yes, but I believe there's another one where I posted a similar
> > incomplete patch and explained why we can't possibly fix this
> > without making points-to analysis useless.
> 
> bug 65752 perhaps?

So Richard, I see you've since had this bug depend on bug 65752, but I thought you said it originally was a dup? If it's not a dup, then this one can be confirmed, right?
Comment 9 Richard Biener 2018-01-08 08:30:58 UTC
Let's mark it as duplicate.

*** This bug has been marked as a duplicate of bug 65752 ***