https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93051

            Bug ID: 93051
           Summary: Wrong optimizations for pointers: `if (p == q) use p`
                    -> `if (p == q) use q`
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ch3root at openwall dot com
  Target Milestone: ---

The optimizer sometimes changes `if (p == q) use p` to `if (p == q) use q` if
it can track the provenance of `q` but not of `p`. This is wrong when the
actual provenance of `p` differs from that of `q`.

Examples demonstrate the problem in different cases:
- with integers and with live pointers (to show that the problem is not in
casts to integers);
- with past-the-end pointers and without them (to show that even changing the
standard to make their comparisons UB will not help);
- with two allocations and with only one (to show that it's not related to how
memory is allocated by the compiler/libc).
Plus, all examples behaves quite well:
- respect provenance of pointers including via casts to integers (so this bug
is not about (im)possibility to clear provenance by casts to integers or
something);
- use only one comparison (so the question of its stability is not touched).

There is some previous analysis of propagation of conditional equivalences in
other bugs, e.g., pr65752#c52, pr61502#c25.

Somewhat more general clang bug -- https://bugs.llvm.org/show_bug.cgi?id=44313.
Previous lengthy discussion is in https://bugs.llvm.org/show_bug.cgi?id=34548.

Example with a past-the-end pointer (the wrong optimization seems to be applied
in vrp1):

----------------------------------------------------------------------
#include <stdio.h>

__attribute__((noipa,optnone)) // imagine it in a separate TU
static void *opaque(void *p) { return p; }

int main()
{
    int x[5];
    int y[1];

    int *p = x;
    int *q = y + 1;

    int *r = opaque(p); // hide provenance of p
    if (r == q) {
        *p = 1;
        *r = 2;
        printf("result: %d\n", *p);
    }

    opaque(q);
}
----------------------------------------------------------------------
$ gcc -std=c11 -pedantic -Wall -Wextra -Wno-attributes test.c && ./a.out
result: 2
$ gcc -std=c11 -pedantic -Wall -Wextra -Wno-attributes -O3 test.c && ./a.out
test.c: In function ‘main’:
test.c:17:9: warning: array subscript 1 is outside array bounds of ‘int[1]’
[-Warray-bounds]
   17 |         *r = 2;
      |         ^~
test.c:9:9: note: while referencing ‘y’
    9 |     int y[1];
      |         ^
result: 1
----------------------------------------------------------------------
gcc x86-64 version: gcc (GCC) 10.0.0 20191223 (experimental)
----------------------------------------------------------------------

The warning nicely illustrates the problem:-)

Based on the example from Harald van Dijk in pr61502#c4.

Reply via email to