C/C++ Indeterminate Values: Compiler optimization gives different output (example)

心已入冬 提交于 2020-01-02 05:50:11

问题


It seems like the C/C++ compiler (clang, gcc, etc) produces different output related to the optimization level. You may as well check the online link included in this post.

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

Based on the following piece of code, could someone explain a few questions 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;
}
  1. Is it certain that the execution will always get into the if statement? How do we know the addresses of the two pointers, p and q, will be the same?
  2. Why does no-optimization has output 14, while -O3 has output 10 for the same instructions?

回答1:


free(p);

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

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

This line has no relevance for p.

if (p == q) {

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

    *p = 10;

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

C++ standard §3.7.4.2/4:

If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

Therefore, the answers to your questions are:

Is it certain that the execution will always get into the if statement?

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

Why does no-optimization has output 14, while -O3 has output 10 for the same instructions?

Because the behaviour is undefined when you dereference an invalid pointer.


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

The value of a pointer to an object whose lifetime has ended is used.

You may find the following question including all comments and answers interesting: Undefined, unspecified and implementation-defined behavior




回答2:


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

This is implementation defined, you cannot rely on this behaviour. p and q can indeed be equal, you have deallocated memory pointed by p, so q might get the same address as p.

Why does no-optimization has output 14, while -O3 has output 10 for the same instructions?

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

https://goo.gl/yRfjIv

where compiler optimizes out assignment of 14, and here version where it looks correct:

https://goo.gl/vSVV0E

value 14 is being assigned, and I have added only one line p = q;

I am not sure why exactly it works like that, I would say that compiler assumes your code is free from undefined behaviour code and does optimizations under such assumption.

[edit]

The Undefined Behaviour is caused by the use of pointer value which compiler assumes is no longer valid, it does not matter if it is later on equal to some newly allocated memory block. The appropriate standard quote was given by TartanLlama :

[basic.stc.dynamic.safety]

[ Note: the effect of using an invalid pointer value (including passing it to a deallocation function) is undefined, see 3.7.4.2. This is true even if the unsafely-derived pointer value might compare equal to some safely-derived pointer value. —end note ]




回答3:


The if-condition may be false -- depending on the particular implementation of malloc() it may return the just-freed block for reuse or a different one.

But, if the program prints anything (because it so happened that q equals p), it must print 14. A compiler producing anything else is buggy...

Using clang 3.4.1 and 3.6.2 here I consistently get the right answer, whereas both gcc 4.2.1 and 5.3.0 manifest the bug. Unfortunately, so does clang 3.8.0.



来源:https://stackoverflow.com/questions/35744832/c-c-indeterminate-values-compiler-optimization-gives-different-output-exampl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!