I built the 3.1 release of llvm/compiler-rt/clang, and I'm trying to see if -fcatch-undefined-behavior really does anything. So far, no luck. E.g. I compile and run
#include <stdio.h>
#include <stdlib.h>
int main() {
int* x = malloc(sizeof(int) * 10);
printf("%d\n", x[20]);
return 0;
}
with
$ /usr/local/bin/clang -fcatch-undefined-behavior undef_test.c && ./a.out
0
Am I missing something really simple?
Yes: x
is not an array.
From the documentation:
-fcatch-undefined-behavior: Turn on runtime code generation to check for undefined behavior. This option, which defaults to off, controls whether or not Clang adds runtime checks for undefined runtime behavior. If a check fails,
__builtin_trap()
is used to indicate failure. The checks are:
- Subscripting where the static type of one operand is a variable which is decayed from an array type and the other operand is greater than the size of the array or less than zero.
- Shift operators where the amount shifted is greater or equal to the promoted bit-width of the left-hand-side or less than zero.
- If control flow reaches __builtin_unreachable.
- When llvm implements more __builtin_object_size support, reads and writes for objects that __builtin_object_size indicates we aren't accessing valid memory. Bit-fields and vectors are not yet checked.
I suppose you wanted to test the subscripting check, unfortunately you did not build an array: you built an area of memory (from malloc
) and then chose to interpret it as an array; but from the point of view of the compiler it is just a chunk of memory (remember than the return type of malloc
is void*
).
You could probably test this behavior with:
int main() {
int x[10] = {};
printf("%d\n", x[20]);
}
Otherwise, for a specific memory issues tracker, you should look into the Address Sanitizer plugin.
-fcatch-undefined-behavior
doesn't handle random pointer dereferences. To handle this case, the compiler would have to store the size of the pointed data alongside the pointer and pass that size in every function call. That would be incompatible with the existing ABI and would require to recompile all the libraries your program link to.
You may argue that malloc
is a well-known function and the compiler could just assume the returned pointer points to an array of the requested size.
But you would be forgetting that malloc
may return NULL
. If the compiler assumed the pointer isn't NULL
, it would optimize out any NULL
checking (quite dangerous). If the compiler assumed the pointer is NULL
or a pointer to an array of the requested size, that would become a little complicated to manage (and we haven't talk of free
and realloc
yet). Moreover any code that dereferences a malloc
-ated pointer without NULL
checking would be considered as undefined behavior.
Not to mention that your program may not link to the standard library but to a library that provides a custom implementation of malloc
with a different semantic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With