wimalopaan
wimalopaan

Reputation: 5462

GCC: null-pointer-checks and undefined-behaviour

The following code does contain UB. The gcc docu says, that the compiler can assume a pointer is non-null after it has been dereferenced. So option <1> and <2> should lead to the same machien-code:

int test(int* p) {
//  *p; // <1> following if is not away 
  *p++; // <2> following if is optimized away
  if (p)
    return 42;
  return *p;
}

But that is not the case: for option <1> the following if is not optimzed away.

What is the reason for the difference?

Upvotes: 0

Views: 81

Answers (2)

Lundin
Lundin

Reputation: 213832

Rather, if the pointer is a null pointer then de-referencing it leads to undefined behavior, period (C17 6.5.3.2 §4). gcc in particular likes to regard that as a free pass to make strange assumptions about code optimizations, where other compilers might instead concern themselves about making rugged programs as close to the programmer's intentions as possible.

What most compilers will do regardless of that, is to optimize out *p;, since it is a no-op. p does not point at volatile-qualified data so de-referencing it is no side effect and the result isn't stored anywhere either.

In case of *p++ there is a side effect since you update where the pointer points at. Performing pointer arithmetic on a null pointer is undefined behavior since it is a constraint violation (C17 6.5.6). So I'm not so sure that removing the if is an intentional optimization or a mishap occurring because of undefined behavior. At any rate, increasing the pointer by 1 makes any assumption of whether it was originally a null pointer or not irrelevant, because you aren't allowed to increment a null pointer by 1 in the first place.

We can't meaningfully reason about code generated while there is undefined behavior present.

Similarly, this code contains undefined behavior if p is not pointing at an array.

Upvotes: 0

Kevin
Kevin

Reputation: 56059

*p++ changes the pointer. The original p has been dereferenced so the compiler assumes it is nonnull. The new address has not been dereferenced, so the compiler does not assume it is nonnull. Could it make such an assumption? Maybe. From my reading of the standards, it's either guaranteed not to overflow or it's undefined behavior, depending on what p originally pointed to and which standard you go by. Feel free to submit it as a feature request to the GCC team and see what they say.

Upvotes: 0

Related Questions