Skip to content

Invalid codegen when comparing pointer to one past the end and then dereferencing that pointer #51912

@GabrielRavier

Description

@GabrielRavier
Bugzilla Link 52570
Version trunk
OS Linux
CC @dwblaikie,@DougGregor,@randomnetcat,@JohelEGP,@momchil-velikov,@zygoloid

Extended Description

extern int x[1], y;

int f(int *p, int *q) {
    *q = y;
    if (p == (x + 1)) {
        *p = 2;
        return y;
    }
    return 0;
}

LLVM trunk currently outputs the following code with -O3 -mtune=znver3 (without it it outputs correct code but I'm pretty sure it still makes the same wrong assumption about the value of p):

f:
        mov     eax, dword ptr [rip + y]
        mov     dword ptr [rsi], eax
        xor     eax, eax
        cmp     rdi, offset x+4
        je      .LBB0_1
        ret
.LBB0_1:
        mov     eax, dword ptr [rip + y]
        mov     dword ptr [rip + x+4], 2
        ret

Which is incorrect because p could point to y, for example if f was called as such:

int whatever;
f(&y, &whatever);

and y could happen to be located in memory right after x.

Also, although the comparison's result is unspecified, this still means only two results are possible according to the standard:

  • if p == (x + 1) results in false, then the result of f is 0
  • if p == (x + 1) results in true, then the result of f is 2 since we do *p = 2 and p points to y

LLVM's optimization makes it so the result can also be the previous value of y, which could be something else than 0 or 2.

It seems that LLVM assumes that because p == (x + 1) it can replace all occurences of p with x + 1 without any regard to provenance, and doing that change manually would indeed mean the return y; could be optimized to use the previous store (and the store to x + 1 would be UB, too...), but this isn't the case here: p could simultaneously validly point to y and be equal to x + 1.

Godbolt link: https://godbolt.org/z/v73ME48qd

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions