1

Possible Duplicate:
Returning the address of local or temporary variable
Can a local variable’s memory be accessed outside its scope?

Suppose we have the following code

int *p;//global pointer
void foo() {
  int a=10;//created in stack
  p = &a;
}//after this a should be deallocated and p should be now a dangling pointer
int main() {
  foo();
  cout << *p << endl;
}

I wanted to know why this works..it should be segment fault!

OK undefined behavior seems appropriate..Can u again verify it? I've tried to simulate the above thing in the following code but now it gives SIGSEGV.

int main() {
    int *p=NULL;
    {
        int i=5;
        int *q = &i;
        p=q;
        delete q;//simulates the deallocation if not deallocated by the destructor..so p becomes a dangling pointer
    }
    cout << *p << endl;
}
Community
  • 1
  • 1
nutr0n
  • 11
  • 2
  • 4
    Undefined behaviour means anything can happen, including appearing to work. – BoBTFish Oct 20 '12 at 08:38
  • Maybe this is one of the reasons why global variables are **bad** – alestanis Oct 20 '12 at 08:39
  • Cleanup may not happen immediately. So it doesn't mean stack on which 'a' is present would be unwinded as soon as function execution finishes. It depends on execution environment, but only thing which we can be sure about is 'it is not safe to do'. – Skandh Oct 20 '12 at 08:42
  • @alestanis: No, this is not one of the reasons why global variables are bad, because the same would have happened if the pointer had been passed as return value. Of course that doesn't mean that global variables aren't bad. It just means this is not an example of why. – celtschk Oct 20 '12 at 08:42
  • @celtschk yes, but with a big fat warning there – alestanis Oct 20 '12 at 08:43
  • @alestanis: No. At the position you `return p;` with a local variable `p` you don't have a warning that this pointer `p` points to the local variable `a` (note that `return p;` with `p` a local variable would be no problem if `p` was initialized with `p = new int(10);`, but then, in that case the global variable wouldn't have given undefined behaviour either). – celtschk Oct 20 '12 at 08:46
  • @celtschk see my answer. That returns a warning that should be treated as an error. – alestanis Oct 20 '12 at 08:57
  • @user1761165 Now you are deleting a pointer which was not allocated by new. That's another form of undefined behaviour. And of course UB covers SIGSEGV as well. Really you should stop trying to reason about programs with UB, just accept that they're bugged and leave it at that. On a side note, you should also understand that deallocation with delete and destruction because of exiting a scope are completely different things, and you cannot simulate one with the other. – john Oct 20 '12 at 09:40
  • @alestanis: In your answer, you eliminated the variable `p` completely, instead of just making it local. Of course, a `return &a` will trigger that warning (indeed, even just having the address-of operator in the return statement would trigger a warning in my head when reading it). But that's not making a global variable locval, that's eliminating a variable altogether. Indeed, the example could be made into an argument why global variables are "better": If `a` were global instead of local, the code would have well-defined behaviour! – celtschk Oct 20 '12 at 10:36

3 Answers3

3

You've written a program that has Undefined Behaviour. UB does not mean segment fault, it means anything could happen. You ran your program and something happened, just not what you expected. Moral of the story is don't write programs with UB, things get very difficult to understand if you do.

john
  • 85,011
  • 4
  • 57
  • 81
1

You shouldn't use global variables. In your example, what you did is an undefined behaviour.

If you had done something like

int* foo() {
  int a = 10; //created in stack
  return &a;
}

int main() {
  int *p = foo();
  cout << *p << endl;
}

You would have gotten a warning at least:

prog.cpp:5: warning: address of local variable ‘a’ returned

You should treat these warnings very seriously.

alestanis
  • 21,519
  • 4
  • 48
  • 67
-1

When you define a variable in the function it will be allocated on the stack and when your return from that function destructor of that variable will be called automatically(if type has any destructor) but unlike heap allocated objects, memory of stack will not freed at this point:

void test1() {
    // assume on start of this function top of stack is 0x100
    int a = 10; // push 10 on to of stack and increase top of stack
                // Now top of stack is 0x100 + sizeof(int)
    a = 20;     // when you do this you are actually changing variable on stack
    p = &a;     // Get address of variable in stack!
                // So p is now 0x100
    // hidden return will restore top of stack to 0x100, pop return address, ...
}
int test2() {
    // again top of stack is 0x100
    int a2;     // a2 is in same address as a in previous function!
    a2 = 100;   // so this will overwrite value that pointed by p
                // because it point to same location
    return (int)&a2;
}

void main() {
    test1();
    test2();
    std::cout << *p << std::endl;
}

But if your type be a class that have a destructor and need a construction before use then you may even receive exceptions like segmentation fault

BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • Compilers don't have to work in the way you are describing. Since the OP's mistake was an incorrect expectation of how his compiler behaved I don't think it helpful to give an answer that has another set of expectations that may or may not actually be true. – john Oct 20 '12 at 08:58
  • @john You call function variable, a stack variable, it will always allocated on stack and it is the nature of stack. If you think against it, please find one compiler that do something other than this. But maybe you are correct about invalid expectation(it is always like this but maybe it used in an invalid way) – BigBoss Oct 20 '12 at 09:18
  • Not necessarily, a compiler could put the variable `a2` in a register for instance. I just ran your program on my compiler (Visual C++, release mode) and it printed out 20, not 100. So you see what you've described is just one possibility, it doesn't have to work like that. – john Oct 20 '12 at 09:43
  • OK, you are right and I just forget optimization, but I want to explain why its program does not generate an error. a UB is still a certain behavior that we don't know it! so I want to explain the behavior – BigBoss Oct 20 '12 at 10:45