Description
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.