0

I have been trying to grasp how local variables inside functions are deallocated once the function execution finishes as the stack frame for that function call is "popped off" the stack.

I wrote some code to test this:

int* func1(void){
    int a = 10; 
    return &a; 
}
int main(void){
    int* h = func1(); 
    printf("%d \n", *h); 

    return 0; 
}

And this resulted in a "segmentation fault.. ", which I expected as that memory at &a is now free.

What I find confusing however is when I create a pointer inside func1 that points to "a" and returns that pointer, the value of "a" seems to persist after.

Here is the code for this:

int* func1(void){
    int a = 10; 
    int* b = &a;
    return b; 
}


int main(void){
    int* h = func1(); 
    printf("%d \n", *h); 

    return 0; 
}

The output I got for this code was "10". Why does this code make "a"'s value persist??

IAhmed12
  • 7
  • 3
  • That's coincidence. Stack space gets reused and is not implicitly initialized when the function starts. – 500 - Internal Server Error Apr 15 '21 at 10:54
  • Thanks for your response, but why does the 2nd code not cause a seg fault? – IAhmed12 Apr 15 '21 at 10:57
  • The stack memory is still there and is available for reading and writing. Segmentation faults occur when the code attempts to access memory that it does not have access to, either because it's deemed off limits by the O/S or the address hasn't been mapped to actual memory at all. – 500 - Internal Server Error Apr 15 '21 at 11:02
  • 1
    Why does the writing on a white board stay there after you leave the room? – Eric Postpischil Apr 15 '21 at 11:03
  • Both examples have [undefined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) so there's no requirement for any specific result from either one. – Blastfurnace Apr 15 '21 at 11:03
  • It's possible that the stack pointer may just be lowered down without actually popping off the variables, so it still exits, but outside the stack, and may be overwritten soon. – mediocrevegetable1 Apr 15 '21 at 11:15
  • 1
    @mediocrevegetable1: Most hardware stacks grow downward. When the stack is popped, the stack pointer is increased, not lowered. – Eric Postpischil Apr 15 '21 at 11:23

1 Answers1

2

Returning the address of a local variable is illegal. Some compilers detects this and instead of returning the actual address of the local variable, the compiler makes the function return a NULL pointer.

That is likely what happens in your first example. So when you dereference the pointer (aka the return value), the program crashes.

In the second example your compiler doesn't detect that the return value is an address of a local variable so the address is actually returned. And when you dereference the pointer (aka the return value), it just happens that the "old" value from the function is still present at that address.

In both cases your code has undefined behavior. What actually happens depends on your specific system.

Try printing the return values like:

int* func1(void){
    int a = 10; 
    printf("In func1: Address of a is %p\n", &a);
    return &a; 
}

int* func2(void){
    int a = 10; 
    printf("In func2: Address of a is %p\n", &a);
    int* b = &a;
    return b; 
}

int main(void){
    int* h = func1(); 
    printf("Value returned by func1:  %p \n", (void*)h); 
    int* hh = func2(); 
    printf("Value returned by func2:  %p \n", (void*)hh); 

    return 0; 
}

My output:

In func1: Address of a is 0x7ffdc3bc0a6c
Value returned by func1:  (nil) 
In func2: Address of a is 0x7ffdc3bc0a6c
Value returned by func2:  0x7ffdc3bc0a6c 

Why does the value of a local variable sometimes persist after the function ends?

Most systems (if not all) use a pre-allocated memory block - called a stack - during function calls. A stack pointer tells how much of that memory block that is currently being used. When a function is called, the stack pointer is changed to use a little more of that memory block (i.e. to store function local variables and possibly other stuff). When the function returns the stack pointer is changed back to the old value again. But it's no required that the memory used by the function is changed in any way. So if you after a function return (illegally) access the stack memory that the function was using, it's likely that you will see the old values still being present.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63