Skip to content

[clang] Taking address of unreachable function can be used to obtain identical integers that compare unequal #60596

@SvizelPritula

Description

@SvizelPritula

Using __builtin_unreachable, it's possible to create a function a that compiles to zero Assembly instructions, like this:

void a() {
    __builtin_unreachable();
}

void b() {}

With -O1 or higher this compiles to:

a:
b:
        ret

The function a is pretty useless, since calling it will unconditionally result in undefined behaviour. It is, however, possible to take its address, like this:

#include <stdlib.h>
#include <stdio.h>

void a() {
    __builtin_unreachable();
}

void b() {}

int main() {
    size_t ap = (size_t) a;
    size_t bp = (size_t) b;

    printf("%zu %zu %d\n", ap, bp, ap == bp);
}

Executing this will reveal that ap and bp have identical values, since a and b have the same address. However, it will also show that ap == bp is false, which contradicts that.

My guess is that some optimization pass assumes that different functions have different addresses, which is required by the C standard.

This bug is unlikely to happen in real programs, since:
a) few programs have functions that have unconditionally undefined behaviour,
b) even fewer programs will take the address of such a function, and
c) fewer still programs compare function pointers.

__builtin_unreachable can also be replaced by other statements with undefined behaviour, such as for (int i=0; i>=0; i++);.

Tested with clang and clang++ 15.0.7 with an optimization level of 1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:codegenIR generation bugs: mangling, exceptions, etc.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions