It looks to me like the following program computes an invalid pointer, since NULL
is no good for anything but assignment and comparison for equality:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *c = NULL;
c--;
printf("c: %p\n", c);
return 0;
}
However, it seems like none of the warnings or instrumentations in GCC or Clang targeted at undefined behavior say that this is in fact UB. Is that arithmetic actually valid and I'm being too pedantic, or is this a deficiency in their checking mechanisms that I should report?
Tested:
$ clang-3.3 -Weverything -g -O0 -fsanitize=undefined -fsanitize=null -fsanitize=address offsetnull.c -o offsetnull
$ ./offsetnull
c: 0xffffffffffffffff
$ gcc-4.8 -g -O0 -fsanitize=address offsetnull.c -o offsetnull
$ ./offsetnull
c: 0xffffffffffffffff
It seems to be pretty well documented that AddressSanitizer as used by Clang and GCC is more focused on dereference of bad pointers, so that's fair enough. But the other checks don't catch it either :-/
Edit: part of the reason that I asked this question is that the -fsanitize
flags enable dynamic checks of well-definedness in the generated code. Is this something they should have caught?
That's because pointers don't behave like integers. It's undefined behavior because the standard says so. On most platforms however (if not all), you won't get a crash or run into dubious behavior if you don't dereference the array.
Since void is an incomplete type, it is not an object type. Therefore it is not a valid operand to an addition operation. Therefore you cannot perform pointer arithmetic on a void pointer.
Null dereferencing In C, dereferencing a null pointer is undefined behavior. Many implementations cause such code to result in the program being halted with an access violation, because the null pointer representation is chosen to be an address that is never allocated by the system for storing objects.
Explanation: What happens here is that when a Null pointer is created, it points to null, without any doubt. But the variable of Null pointer takes some memory. Hence when a pointer to a null pointer is created, it points to an actual memory space, which in turn points to null.
Pointer arithmetic on a pointer not pointing to an array is Undefined behavior.
Also, Dereferencing a NULL pointer is undefined behavior.
char *c = NULL;
c--;
is Undefined defined behavior because c
does not point to an array.
C++11 Standard 5.7.5:
When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
Yes, this is undefined behavior, and is something that -fsanitize=undefined
should have caught; it's already on my TODO list to add a check for this.
FWIW, the C and C++ rules here are slightly different: adding 0
to a null pointer and subtracting one null pointer from another have undefined behavior in C but not in C++. All other arithmetic on null pointers has undefined behavior in both languages.
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