C / C ++ Undefined values: compiler optimization gives different output (example)

It seems that the C / C ++ compiler (clang, gcc, etc.) produces different results related to the level of optimization. You can also check the online link included in this post.

http://cpp.sh/5vrmv (change the output from none to -O3 to see the differences).

Based on the following code snippet, can someone explain a few questions that I have:

#include <stdio.h> #include <stdlib.h> int main(void) { int *p = (int *)malloc(sizeof(int)); free(p); int *q = (int *)malloc(sizeof(int)); if (p == q) { *p = 10; *q = 14; printf("%d", *p); } return 0; } 
  • Is it possible that execution will always be part of the if statement? How do we know that the addresses of two pointers, p and q, will be the same?
  • Why does no-optimization have output 14 , and for -O3 output 10 for the same instructions?
+4
source share
3 answers
 free(p); 

This turns the contents of p into an invalid pointer value.

 int *q = (int *)malloc(sizeof(int)); 

This line is not related to p .

 if (p == q) { 

This is implementation-defined behavior because p has an invalid pointer value.

  *p = 10; 

And finally, this behavior is undefined for the same reason as above.

C ++ Standard ยง3.7.4.2 / 4:

If the argument assigned to the maladaptation function in the standard library is a pointer that is not a null pointer value (4.10), the release function frees up the storage location that the pointer refers to, rendering is invalid for all pointers that reference any part of the freed storage. Direction using an invalid pointer value and passing an invalid pointer value to the release function undefined behavior . Any other use of an invalid pointer value has a behavior defined by the implementation.

Therefore, the answers to your questions:

Is it possible that execution will always be part of the if statement?

It depends on the implementation. C ++ does not guarantee it.

Why does no-optimization have an output of 14, and -O3 has an output of 10 for the same instructions?

Because undefined behavior occurs when dereferencing an invalid pointer.


In C, comparison itself is undefined behavior. Appendix J.2 in the C standard lists circumstances in which the behavior is undefined, and this list includes:

The value of the pointer to the object whose lifetime has expired is used.

You can find the following question, including all comments and answers: Undefined, undefined and implementation-specific behavior

+4
source

Is it possible that execution will always be part of the if statement? How do we know that the addresses of two pointers, p and q, will be the same?

This is a specific implementation; you cannot rely on this behavior. p and q can indeed be equal, you have freed the memory indicated by p , so q can get the same address as p .

Why does no-optimization have an output of 14, and -O3 has an output of 10 for the same instructions?

here is how the optimizer works, you can see your version here:

https://goo.gl/yRfjIv

where the compiler optimizes the assignment to 14, and here is the version where it looks right:

https://goo.gl/vSVV0E

a value of 14 is assigned, and I added only one line p = q;

I'm not sure why this works, I would say that the compiler assumes that your code is free from undefined behavior code and does optimization under such an assumption.

[edit]

The undefined behavior is caused by the use of a pointer value, which, according to the compiler, is no longer valid, it does not matter whether it will later be equal to some newly allocated memory block. An appropriate standard quote was given by TartanLlama:

[basic.stc.dynamic.safety]

[Note: the effect of using an invalid pointer value (including passing it to the release function) is undefined, see 3.7.4.2. This is true even if the value of the pointer, insensitive to the derivative, compare the value equal to some safely obtained value of the pointer. -end note]

0
source

The if condition may be false - depending on the particular implementation of malloc() it may return a newly released block for reuse or another.

But if the program prints something (because it so happened that q is equal to p ), it should print 14 . The compiler creating anything else does not work ...

Using clang 3.4.1 and 3.6.2 here, I consistently get the correct answer, while gcc 4.2.1 and 5.3.0 show an error. Unfortunately, clang 3.8.0 is also.

-3
source

Source: https://habr.com/ru/post/1265668/


All Articles