Bug 63611 - Invalid optimization for "==" on pointers
Summary: Invalid optimization for "==" on pointers
Status: RESOLVED DUPLICATE of bug 61502
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.8.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-21 19:15 UTC by Keith Thompson
Modified: 2024-01-25 23:16 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Keith Thompson 2014-10-21 19:15:23 UTC
"gcc --version" says
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

"uname -a" says
Linux bomb20 3.13.0-24-generic #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
(The system is Linux Mint 17, based on Ubuntu 14.04.1 LTS.)

I've created a Gist at
https://gist.github.com/Keith-S-Thompson/60dc069f4823fb1c3209
but of course I'll include the information here.

The C standard's definition of "==" for pointers (N1570 6.5.9 paragraph 6) says:

Two pointers compare equal if and only if both are null pointers, both
are pointers to the same object (including a pointer to an object and a
subobject at its beginning) or function, both are pointers to one past
the last element of the same array object, or one is a pointer to one
past the end of one array object and the other is a pointer to the start
of a different array object that happens to immediately follow the first
array object in the address space.

which implies that the test program below should print (among other output)
one of the following:
- "y immediately follows x" followed by "ok";
- "x immediately follows y" followed by "ok"; or
- "x and y are not adjacent"

Instead, when compiled with gcc, it prints "inconsistent behavior: ...".

It appears that gcc is assuming that a pointer just past the end of one
declared object cannot be equal to a pointer to the beginning of another
object, when the two objects are not subobjects of the same containing
object. Examining an assembly listing indicates that the code to print
"ok" is not even generated, implying that this is an optimization bug
(that occurs even at "-O0".

I don't expect that this is a common use case, but the compiled program
does behave in a manner inconsistent with the standard's requirements.

I see the same behavior with a copy of gcc 4.9.1 built from source on the
same system.  (I also see it with clang 3.5-1ubuntu1, but with the order
of x and y reversed; that's not directly relevant to this bug report,
but it's mildly interesting.)

The command line used to compile and execute the program is:

$ gcc -std=c11 -pedantic -Wall -Wextra pointer_equality_bug.c -o pointer_equality_bug && ./pointer_equality_bug

The output on my system is:

x  = 0x7fff2a94a1d0
x0 = 0x7fff2a94a1d0
x1 = 0x7fff2a94a250
y  = 0x7fff2a94a250
y0 = 0x7fff2a94a250
y1 = 0x7fff2a94a2d0
y immediately follows x
inconsistent behavior:
    0x7fff2a94a250 !=
    0x7fff2a94a250

And the program itself (73 lines, making up the remainder of this description) is:

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    typedef struct {
        int arr[32];
    } element;
    element x[1];
    element y[1];
    element *const x0 = x;
    element *const x1 = x0 + 1;
    element *const y0 = y;
    element *const y1 = y0 + 1;

    /*
     * x and y will typically be adjacent in memory.
     * x0 points to x; x1 points just past it.
     * y0 points to y; y1 points just past it.
     * We should have x1 == y0 if and only if y immediately follows x.
     * We should have y1 == x0 if and only if x immediately follows y.
     */

    printf("x  = %p\nx0 = %p\nx1 = %p\ny  = %p\ny0 = %p\ny1 = %p\n",
           (void*)x, (void*)x0, (void*)x1,
           (void*)y, (void*)y0, (void*)y1);

    if (x1 == y0) {
        puts("y immediately follows x");
        if (x + 1 == y) {
            puts("ok");
        }
        else if (x + 1 != y) {
            printf("inconsistent behavior:\n"
                   "    %p !=\n"
                   "    %p\n",
                   (void*)(x + 1),
                   (void*)y);
            exit(EXIT_FAILURE);
        }
        else {
            printf("inconsistent behavior:\n"
                   "    %p !=\n"
                   "    %p\n",
                   (void*)(x + 1),
                   (void*)y);
            exit(EXIT_FAILURE);
        }
    }
    else if (y1 == x0) {
        puts("x immediately follows y");
        if (y + 1 == x) {
            puts("ok");
        }
        else if (y + 1 != x) {
            printf("inconsistent behavior:\n"
                   "    %p !=\n"
                   "    %p\n",
                   (void*)(y + 1),
                   (void*)x);
            exit(EXIT_FAILURE);
        }
        else {
            printf("inconsistent behavior:\n"
                   "    %p !=\n"
                   "    %p\n",
                   (void*)(y + 1),
                   (void*)x);
            exit(EXIT_FAILURE);
        }
    }
    else {
        puts("x and y are not adjacent");
    }
}
Comment 1 Keith Thompson 2014-10-21 19:34:33 UTC
A bug report for a similar issue with clang is here:
http://llvm.org/bugs/show_bug.cgi?id=21327
Comment 2 Joseph S. Myers 2014-10-21 21:42:09 UTC
See bug 61502.  The last comment there appears to indicate a bug, but the test given here doesn't based on my understanding that whether two objects follow each other need not be constant for all comparisons.

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