6

This code:

#include <iostream>

using namespace std;

int* fun()
{
    int a = 5;
    int* pointerA = &a;

    cout << pointerA << endl;

    return pointerA;
}

int main()
{

    int* p = fun();

    cout << p << endl;

    return 0;
}

Prints the following:

0x[some address]
0

I understand that the variable a is deallocated when the function fun() returns, but why does cout << p << endl; return 0? Shouldn't it still point to the same address in memory, even though variable is technically not there anymore? Is this a compiler feature or undefined behavior?

repro case

EDIT: I found the culprit. I am using CodeBlocks, and in this project's build options, there is a flag "optimize even more (for speed) [-O2]". If it is checked, I get 0, and if I uncheck the flag, I get the same address 0x[some address], which is expected behavior.

I apologize for not mentioning my IDE.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
user3007875
  • 123
  • 7
  • 1
    Cannot reproduce this behavior on macOS with clang 10.0.1 nor on Linux with gcc 6.3. – Botje Jul 31 '19 at 08:59
  • 1
    Interesting, doesn't happen on debug only on release builds. I thought it'd be the other way around. – Hatted Rooster Jul 31 '19 at 09:02
  • What compiler are you using? – SilverTear Jul 31 '19 at 09:03
  • 2
    *Shouldn't it still point to the same address in memory, even though variable is technically not there anymore?* -- The compiler's optimizer does amazing things when you write stuff like this, agree? You know it's code that may not work, but at the same time you're saying "it should work". – PaulMcKenzie Jul 31 '19 at 09:04
  • 1
    https://wandbox.org/permlink/I5LRpUCWcA4mL0YO here is the repro case – Hatted Rooster Jul 31 '19 at 09:04
  • 2
    Which means that somewhere this code _is_ in fact UB, otherwise the optimizer wouldn't be allowed to optimize this. – Hatted Rooster Jul 31 '19 at 09:05
  • 6
    Returning a pointer to a local variable and then accessing such pointer is undefined behavior. It doesn't matter how benign the access of the pointer may be -- the behavior is undefined. – PaulMcKenzie Jul 31 '19 at 09:07
  • 1
    @PaulMcKenzie UB is only accessing the value it points to (which is not in case here). – user7860670 Jul 31 '19 at 09:12
  • Tempted to post a question for the general case. – Hatted Rooster Jul 31 '19 at 09:20
  • 2
    @VTT from [basic.stc.dynamic.deallocation]: `The effect of using an invalid pointer value (including passing it to a deallocation function) is undefined.` Does "using an invalid pointer value" not include OP's case? – kakkoko Jul 31 '19 at 09:49
  • I found the solution, check the OP's post. – user3007875 Jul 31 '19 at 10:05
  • @kakkoko The quoted block seems to be from notes, which are non-normative. And the wording is rather strange. I mean if accessing even the *object representation* of the invalid pointer is UB then using null pointers in any form would be UB as well which makes no sense. – user7860670 Jul 31 '19 at 10:09
  • @VTT Sorry, I was looking at an old standard. In C++14, this part was changed to `Any other use of an invalid pointer value has implementation-defined behavior.` – kakkoko Jul 31 '19 at 10:26
  • @user3007875 That's not a solution, it just removes the optimized code from UB. – Hatted Rooster Jul 31 '19 at 10:47
  • @SombreroChicken Solution is that compiler optimizes pointer to null, when local variable that said pointer pointed to, is deallocated. Am I thinking wrong? – user3007875 Jul 31 '19 at 11:04
  • 1
    Yes that's correct but the interesting part would be where the standard says its UB – Hatted Rooster Jul 31 '19 at 11:16
  • 2
    _Shouldn't it still point to the same address in memory_ Meaningless question. Invalid pointer values do not represent addresses. – Language Lawyer Jul 31 '19 at 21:02

2 Answers2

3

Accessing the return value of fun has implementation-defined behavior, as it returns an invalid pointer value (see the quote below, why). In particular platforms, it may even generate a runtime fault. So, p's value is implementation-defined as well. Most likely, it will became invalid pointer value, so accessing it is implementation-defined.

basic.std/4:

When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values. 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.

geza
  • 28,403
  • 6
  • 61
  • 135
2

It is probably a compiler feature. In this case it is very easy to see that the pointer returned by fun will be invalid and thus further usage of the pointer will result in undefined behaviour. If you try a different compiler it might be different. E.g. for me in Visual Studio 2012 it does return the actual address instead of 0.

SilverTear
  • 695
  • 7
  • 18